@libraz/mejiro-react 0.10.0 → 0.11.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 +1 -0
- package/dist/index.d.ts +1187 -1004
- package/dist/index.js +2009 -1637
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { MejiroLocale, MejiroMessages, EditableSettings, FontChoice, ImageOverlayRect, PageHeaderData,
|
|
2
|
-
export { Annotation, EditableSettings, FontChoice, ImageOverlayRect, MejiroLocale, MejiroMessages, PageHeaderData,
|
|
1
|
+
import { MejiroLocale, MejiroMessages, EditableSettings, FontChoice, MejiroStorage, Annotation, MejiroError, ImageOverlayRect, PageHeaderData, BinaryInput, ManuscriptChapter as ManuscriptChapter$1, InlineAnnotation, ReadingAnchor as ReadingAnchor$1 } from '@libraz/mejiro';
|
|
2
|
+
export { Annotation, EditableSettings, FontChoice, ImageOverlayRect, ManuscriptChapter, MejiroError, MejiroErrorCode, MejiroLocale, MejiroMessages, MejiroStorage, MejiroWarning, MejiroWarningCode, PageHeaderData, ReadingAnchor, enMessages, formatMessage, jaMessages, resolveMessages } from '@libraz/mejiro';
|
|
3
3
|
import * as react from 'react';
|
|
4
|
-
import { ReactNode, CSSProperties, PointerEvent, TextareaHTMLAttributes,
|
|
5
|
-
import { EpubBook,
|
|
4
|
+
import { ReactNode, ComponentPropsWithoutRef, CSSProperties, PointerEvent, TextareaHTMLAttributes, RefAttributes, RefObject, MutableRefObject } from 'react';
|
|
5
|
+
import { EpubBook, EpubParseLimits, ManuscriptDialect, AssetResolver, EditableEpub, EpubChapter, EditableEpubBook, EditHistoryState, EditableEpubSelection, EditableParagraphBlock, ParagraphPatch, AddImageInput, EditableImageBlock, EditableEpubExportOptions, EpubProjectMetadata, CoverInput, EpubProjectAsset, EpubProject } from '@libraz/mejiro/epub';
|
|
6
6
|
export { EditableEpubSelection } from '@libraz/mejiro/epub';
|
|
7
|
-
import { ChapterLayout,
|
|
7
|
+
import { SpreadResult, ChapterLayout, InChapterAnchor, AnchorRect, SpreadPoint, AnchorRange, BookOptions, FitPageSizeOptions, ReadingAnchor, BookOptionsPatch, ManuscriptChapter, PageResult, MejiroBook } from '@libraz/mejiro/book';
|
|
8
8
|
import { PageNumberDisplay, RenderPage } from '@libraz/mejiro/render';
|
|
9
9
|
export { PageNumberDisplay } from '@libraz/mejiro/render';
|
|
10
|
-
import { FontFamily
|
|
10
|
+
import { FontFamily } from '@libraz/mejiro/browser';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/** Props for {@link MejiroI18nProvider}. */
|
|
13
|
+
interface MejiroI18nProviderProps {
|
|
14
|
+
/**
|
|
15
|
+
* Built-in locale to use as the base catalog. Without it the catalog of the
|
|
16
|
+
* enclosing provider is the base, or the English catalog at the top level.
|
|
17
|
+
*/
|
|
14
18
|
locale?: MejiroLocale;
|
|
19
|
+
/** Overrides merged on top of the base catalog. */
|
|
15
20
|
messages?: Partial<MejiroMessages>;
|
|
21
|
+
/** Subtree the catalog applies to. */
|
|
16
22
|
children: ReactNode;
|
|
17
|
-
}
|
|
23
|
+
}
|
|
24
|
+
/** Provider that scopes a message catalog to its descendants. */
|
|
25
|
+
declare function MejiroI18nProvider({ locale, messages, children, }: MejiroI18nProviderProps): ReactNode;
|
|
18
26
|
/** Options for {@link useI18n}. */
|
|
19
27
|
interface UseI18nOptions {
|
|
20
28
|
/**
|
|
@@ -31,45 +39,45 @@ interface UseI18nOptions {
|
|
|
31
39
|
* passing `locale` / `messages` resolves a catalog without context.
|
|
32
40
|
*/
|
|
33
41
|
declare function useI18n(options?: UseI18nOptions): MejiroMessages;
|
|
34
|
-
/** Build a catalog without invoking React (useful in plain modules). */
|
|
35
|
-
declare function resolveMessages(locale: MejiroLocale | undefined, overrides: Partial<MejiroMessages> | undefined): MejiroMessages;
|
|
36
|
-
/** Replace `{name}` placeholders in a template. */
|
|
37
|
-
declare function format(template: string, vars: Record<string, string | number>): string;
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
44
|
* Layout of {@link MejiroChapterNav}: `'select'` is a compact dropdown,
|
|
41
45
|
* `'panel'` a chapter list with titles, headings and a text preview.
|
|
42
46
|
*/
|
|
43
47
|
type MejiroChapterNavVariant = 'select' | 'panel';
|
|
44
|
-
/** Props for {@link MejiroChapterNav}. */
|
|
45
|
-
interface MejiroChapterNavProps {
|
|
48
|
+
/** Props for {@link MejiroChapterNav}; other `div` attributes go to the root element. */
|
|
49
|
+
interface MejiroChapterNavProps extends ComponentPropsWithoutRef<'div'> {
|
|
46
50
|
/** EPUB to list chapters from. */
|
|
47
51
|
epub: EpubBook;
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
/** Called
|
|
51
|
-
|
|
52
|
+
/** Zero-based index of the chapter shown as current. */
|
|
53
|
+
chapterIndex: number;
|
|
54
|
+
/** Called with the zero-based index of the chapter the user picks. */
|
|
55
|
+
onChapterIndexChange: (chapterIndex: number) => void;
|
|
52
56
|
/** Visual treatment for the chapter list. @defaultValue 'select' */
|
|
53
57
|
variant?: MejiroChapterNavVariant;
|
|
54
58
|
}
|
|
55
59
|
/**
|
|
56
|
-
* Chapter
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* more accessible markup. `MejiroChapterNav` remains supported for the
|
|
61
|
-
* `<select>` variant and existing `MejiroReader` integration.
|
|
60
|
+
* Chapter picker for an {@link EpubBook}: a compact `<select>`, or a panel
|
|
61
|
+
* listing each chapter with its sub-headings and a text preview. For a
|
|
62
|
+
* searchable table of contents that follows the reading anchor, use
|
|
63
|
+
* {@link MejiroToc}.
|
|
62
64
|
*/
|
|
63
|
-
declare
|
|
65
|
+
declare const MejiroChapterNav: react.ForwardRefExoticComponent<MejiroChapterNavProps & react.RefAttributes<HTMLElement>>;
|
|
64
66
|
|
|
65
|
-
/** Props for {@link MejiroDropZone}. */
|
|
66
|
-
interface MejiroDropZoneProps {
|
|
67
|
+
/** Props for {@link MejiroDropZone}; other `button` attributes go to the root element. */
|
|
68
|
+
interface MejiroDropZoneProps extends ComponentPropsWithoutRef<'button'> {
|
|
67
69
|
/** File `accept` filter for the picker. @defaultValue '.epub' */
|
|
68
70
|
accept?: string;
|
|
69
71
|
/** Validator. Defaults to the `accept` filter, with extensions matched case-insensitively. */
|
|
70
72
|
validateFile?: (file: File) => boolean;
|
|
71
73
|
/** Called with the selected/dropped file. */
|
|
72
74
|
onFile: (file: File) => void;
|
|
75
|
+
/**
|
|
76
|
+
* Called with a selected or dropped file that is not accepted: `'type'` when
|
|
77
|
+
* it fails the `accept` filter, `'validation'` when
|
|
78
|
+
* {@link MejiroDropZoneProps.validateFile} returns `false`.
|
|
79
|
+
*/
|
|
80
|
+
onReject?: (file: File, reason: 'type' | 'validation') => void;
|
|
73
81
|
/** Custom body content (replaces default icon/text). */
|
|
74
82
|
children?: ReactNode;
|
|
75
83
|
/** Additional class name for the root element. */
|
|
@@ -82,18 +90,21 @@ interface MejiroDropZoneProps {
|
|
|
82
90
|
* picker. The root is a real button, so it is reachable with Tab, announced as
|
|
83
91
|
* a control by screen readers, and opens the picker on Enter / Space.
|
|
84
92
|
*/
|
|
85
|
-
declare
|
|
93
|
+
declare const MejiroDropZone: react.ForwardRefExoticComponent<MejiroDropZoneProps & react.RefAttributes<HTMLButtonElement>>;
|
|
86
94
|
|
|
87
|
-
/** Props for {@link MejiroSettingsPanel}. */
|
|
88
|
-
interface MejiroSettingsPanelProps {
|
|
95
|
+
/** Props for {@link MejiroSettingsPanel}; other `div` attributes go to the root element. */
|
|
96
|
+
interface MejiroSettingsPanelProps extends ComponentPropsWithoutRef<'div'> {
|
|
89
97
|
/** Whether the panel is expanded. */
|
|
90
98
|
open: boolean;
|
|
91
99
|
/** Current editable settings. */
|
|
92
100
|
settings: EditableSettings;
|
|
93
|
-
/**
|
|
94
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Called when the user changes a setting, with the whole settings value:
|
|
103
|
+
* {@link MejiroSettingsPanelProps.settings} with that one field replaced.
|
|
104
|
+
*/
|
|
105
|
+
onSettingsChange: (next: EditableSettings) => void;
|
|
95
106
|
/** Font choices. */
|
|
96
|
-
fonts?: FontChoice[];
|
|
107
|
+
fonts?: readonly FontChoice[];
|
|
97
108
|
/** Min font size. @defaultValue 10 */
|
|
98
109
|
minFontSize?: number;
|
|
99
110
|
/** Max font size. @defaultValue 48 */
|
|
@@ -102,181 +113,427 @@ interface MejiroSettingsPanelProps {
|
|
|
102
113
|
/**
|
|
103
114
|
* Reader settings panel: font, size, kinsoku mode, hanging punctuation, line spacing.
|
|
104
115
|
*/
|
|
105
|
-
declare
|
|
116
|
+
declare const MejiroSettingsPanel: react.ForwardRefExoticComponent<MejiroSettingsPanelProps & react.RefAttributes<HTMLDivElement>>;
|
|
106
117
|
|
|
107
|
-
/**
|
|
108
|
-
interface
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
/** Font choices passed to the preview reader. */
|
|
112
|
-
fonts?: FontChoice[];
|
|
113
|
-
/**
|
|
114
|
-
* Allow editing paragraph text (the "Proofread" section). When `false` and
|
|
115
|
-
* `enableRuby` is on, the paragraph text stays visible read-only so a ruby
|
|
116
|
-
* base range can still be selected.
|
|
117
|
-
* @defaultValue true
|
|
118
|
-
*/
|
|
119
|
-
enableProofread?: boolean;
|
|
120
|
-
/**
|
|
121
|
-
* Allow editing ruby annotations (the "Ruby" section).
|
|
122
|
-
* @defaultValue true
|
|
123
|
-
*/
|
|
124
|
-
enableRuby?: boolean;
|
|
125
|
-
/**
|
|
126
|
-
* Allow inserting images into the EPUB (the "Images" section).
|
|
127
|
-
* @defaultValue true
|
|
128
|
-
*/
|
|
129
|
-
enableImages?: boolean;
|
|
130
|
-
/**
|
|
131
|
-
* Allow exporting the edited EPUB. SaaS publishers can disable this to
|
|
132
|
-
* restrict downloads (e.g. server-side export only).
|
|
133
|
-
* @defaultValue true
|
|
134
|
-
*/
|
|
135
|
-
enableExport?: boolean;
|
|
136
|
-
/**
|
|
137
|
-
* Called before the export buffer is offered as a download. Return `false`
|
|
138
|
-
* (or a `Promise<false>`) to suppress the browser download — useful for
|
|
139
|
-
* uploading the buffer to a backend instead.
|
|
140
|
-
*/
|
|
141
|
-
onBeforeExport?: (buffer: ArrayBuffer) => boolean | undefined | Promise<boolean | undefined>;
|
|
118
|
+
/** Options for {@link useAnnotations}. */
|
|
119
|
+
interface UseAnnotationsOptions {
|
|
120
|
+
/** Storage key — usually scoped per-book (e.g. `mejiro:annotations:${bookId}`). */
|
|
121
|
+
key: string;
|
|
142
122
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
123
|
+
* Storage backend. Defaults to `window.localStorage` when available.
|
|
124
|
+
* SSR consumers can omit this and the hook will fall back to in-memory.
|
|
125
|
+
* The latest reference is always used, so an object literal recreated on
|
|
126
|
+
* every render is safe — only `key` triggers a re-hydration.
|
|
146
127
|
*/
|
|
147
|
-
|
|
128
|
+
storage?: MejiroStorage;
|
|
148
129
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* them once when the EPUB is assembled — e.g. signed S3 URLs that require
|
|
153
|
-
* custom auth headers.
|
|
130
|
+
* Debounce delay (ms): the latest value is written this long after the last
|
|
131
|
+
* change. A pending write is flushed on page hide, key change and unmount.
|
|
132
|
+
* @defaultValue 250
|
|
154
133
|
*/
|
|
155
|
-
|
|
134
|
+
debounceMs?: number;
|
|
156
135
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
136
|
+
* Called immediately after each mutation (`add` / `remove` / `update` /
|
|
137
|
+
* `clear`) with the new annotation list. Use to mirror state to a server
|
|
138
|
+
* — `storage` only covers the local persistence side. Not invoked on
|
|
139
|
+
* initial hydration or when the `key` changes.
|
|
160
140
|
*/
|
|
161
|
-
|
|
162
|
-
/** Called after an EPUB is loaded into the editor. */
|
|
163
|
-
onLoad?: (editor: EditableEpub) => void;
|
|
164
|
-
/** Called after export completes. */
|
|
165
|
-
onExport?: (buffer: ArrayBuffer) => void;
|
|
141
|
+
onAnnotationsChange?: (next: readonly Annotation[]) => void;
|
|
166
142
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* or
|
|
143
|
+
* Receives a storage failure: `storage-read-failed` or `storage-corrupt` when
|
|
144
|
+
* hydrating (the list starts empty, and the stored value is left alone until
|
|
145
|
+
* the next mutation), `storage-write-failed` when a write or removal throws
|
|
146
|
+
* (the in-memory list is kept). Without it the error goes to `console.warn`.
|
|
170
147
|
*/
|
|
171
|
-
onError?: (error:
|
|
148
|
+
onError?: (error: MejiroError) => void;
|
|
172
149
|
}
|
|
173
|
-
/**
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
*/
|
|
186
|
-
allowDownload?: boolean;
|
|
187
|
-
/**
|
|
188
|
-
* Transforms the EPUB buffer before it is offered for download. Typically
|
|
189
|
-
* a server round-trip that returns a DRM-wrapped EPUB.
|
|
190
|
-
*/
|
|
191
|
-
encrypt?: (buffer: ArrayBuffer) => ArrayBuffer | Promise<ArrayBuffer>;
|
|
192
|
-
/**
|
|
193
|
-
* Embeds a visible watermark string into the exported EPUB. Implemented as a
|
|
194
|
-
* paragraph block prefixed with `[mejiro-watermark]` at the top of every
|
|
195
|
-
* chapter, so a downstream renderer can theme it by that prefix. The block
|
|
196
|
-
* only exists in the exported file — the edited document is unchanged.
|
|
197
|
-
*/
|
|
198
|
-
watermark?: {
|
|
199
|
-
text: string;
|
|
200
|
-
};
|
|
150
|
+
/** Return value of {@link useAnnotations}. */
|
|
151
|
+
interface UseAnnotationsReturn {
|
|
152
|
+
/** Currently saved annotations, sorted by chapter / paragraph / charIndex. */
|
|
153
|
+
annotations: readonly Annotation[];
|
|
154
|
+
/** Add a new annotation. `id` and `createdAt` are auto-filled when omitted. */
|
|
155
|
+
add(input: Omit<Annotation, 'id' | 'createdAt'> & Partial<Pick<Annotation, 'id' | 'createdAt'>>): Annotation;
|
|
156
|
+
/** Remove an annotation by id. */
|
|
157
|
+
remove(id: string): void;
|
|
158
|
+
/** Patch an annotation by id. Pass `undefined` on a field to leave it untouched. */
|
|
159
|
+
update(id: string, patch: Partial<Omit<Annotation, 'id'>>): void;
|
|
160
|
+
/** Remove all annotations. */
|
|
161
|
+
clear(): void;
|
|
201
162
|
}
|
|
202
|
-
/** EPUB editor UI for proofreading, ruby edits, image insertion, and export. */
|
|
203
|
-
declare function MejiroEditor({ epubUrl, fonts, enableProofread, enableRuby, enableImages, enableExport, onBeforeExport, exportPolicy, assetResolver, limits, onLoad, onExport, onError, }: MejiroEditorProps): ReactNode;
|
|
204
|
-
|
|
205
163
|
/**
|
|
206
|
-
*
|
|
164
|
+
* Persistence helper for reader annotations. Returns the saved annotation list
|
|
165
|
+
* plus add / update / remove helpers. Pair with the `annotations` prop on
|
|
166
|
+
* {@link MejiroReader} to render the corresponding highlight rectangles.
|
|
167
|
+
*
|
|
168
|
+
* ```tsx
|
|
169
|
+
* const { annotations, add } = useAnnotations({ key: `mejiro:ann:${bookId}` });
|
|
170
|
+
* const handle = useRef<MejiroReaderHandle>(null);
|
|
171
|
+
*
|
|
172
|
+
* // Save a highlight at the current visible range:
|
|
173
|
+
* const range = handle.current?.getVisibleRange();
|
|
174
|
+
* if (range) add({ chapterIndex: 0, start: range.start, end: range.end, color: 'yellow' });
|
|
207
175
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* `ImageRect` (an exclusion rectangle, with margin fields), so the two names
|
|
211
|
-
* collide when both packages are imported into one module.
|
|
176
|
+
* <MejiroReader epub={book} annotations={annotations} ref={handle} />
|
|
177
|
+
* ```
|
|
212
178
|
*/
|
|
213
|
-
|
|
179
|
+
declare function useAnnotations(options: UseAnnotationsOptions): UseAnnotationsReturn;
|
|
180
|
+
|
|
181
|
+
/** A single image overlay placed on a specific spread. */
|
|
182
|
+
interface MultiImageItem {
|
|
183
|
+
/** Stable ID for the overlay (auto-assigned on add). */
|
|
184
|
+
id: string;
|
|
185
|
+
/** Position and size in pixels, relative to the right page. */
|
|
186
|
+
rect: ImageOverlayRect;
|
|
187
|
+
}
|
|
214
188
|
/** Options for {@link useImageOverlay}. */
|
|
215
189
|
interface UseImageOverlayOptions {
|
|
216
|
-
/**
|
|
190
|
+
/** Layout spread that {@link UseImageOverlayReturn.addOverlay} places overlays on. */
|
|
191
|
+
spreadIndex: number;
|
|
192
|
+
/** Default overlay width in pixels. @defaultValue 120 */
|
|
217
193
|
defaultWidth?: number;
|
|
218
|
-
/** Default
|
|
194
|
+
/** Default overlay height in pixels. @defaultValue 160 */
|
|
219
195
|
defaultHeight?: number;
|
|
220
|
-
/** Default x position. @defaultValue 80 */
|
|
196
|
+
/** Default x position, relative to the right page. @defaultValue 80 */
|
|
221
197
|
defaultX?: number;
|
|
222
198
|
/** Default y position. @defaultValue 100 */
|
|
223
199
|
defaultY?: number;
|
|
224
|
-
/** Margin around
|
|
200
|
+
/** Margin around each overlay, in pixels. Defaults to the book's font size. */
|
|
225
201
|
margin?: number;
|
|
202
|
+
/**
|
|
203
|
+
* Called with each spread the layout re-flowed after an overlay change, and
|
|
204
|
+
* after the overlays are re-applied to a replacement layout or a new margin.
|
|
205
|
+
* Pair it with `useSpread().refresh()` so the spread on screen picks up the
|
|
206
|
+
* reflow. @defaultValue no-op
|
|
207
|
+
*/
|
|
208
|
+
onReflow?: (spread: SpreadResult) => void;
|
|
226
209
|
}
|
|
227
210
|
/** Return value of {@link useImageOverlay}. */
|
|
228
211
|
interface UseImageOverlayReturn {
|
|
229
|
-
/**
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Overlays keyed by spread index. A new map whenever the overlays or the
|
|
214
|
+
* margin they are applied with change, and a replacement layout has them
|
|
215
|
+
* before any view renders from it, so this map and the layout together key
|
|
216
|
+
* anything derived from the layout.
|
|
217
|
+
*/
|
|
218
|
+
imagesBySpread: ReadonlyMap<number, readonly MultiImageItem[]>;
|
|
219
|
+
/** Overlays on {@link UseImageOverlayOptions.spreadIndex}; a new array whenever `imagesBySpread` changes. */
|
|
220
|
+
currentImages: readonly MultiImageItem[];
|
|
221
|
+
/** Whether any spread holds at least one overlay. */
|
|
222
|
+
hasOverlays: boolean;
|
|
223
|
+
/** Adds an overlay on the current spread and returns it. */
|
|
224
|
+
addOverlay: (overrides?: Partial<ImageOverlayRect>) => MultiImageItem;
|
|
225
|
+
/** Removes the overlay with the given id; a no-op for an unknown id. */
|
|
226
|
+
removeOverlay: (id: string) => void;
|
|
227
|
+
/** Merges `rect` into the rectangle of the overlay with the given id; a no-op for an unknown id. */
|
|
228
|
+
updateOverlay: (id: string, rect: Partial<ImageOverlayRect>) => void;
|
|
229
|
+
/** Removes every overlay, or only those on `spreadIndex` when given. */
|
|
230
|
+
clearOverlays: (spreadIndex?: number) => void;
|
|
231
|
+
/** Pointer-down handler for an overlay body: starts a move drag. */
|
|
232
|
+
onOverlayPointerDown: (id: string, e: PointerEvent) => void;
|
|
233
|
+
/** Pointer-down handler for an overlay's resize handle: starts a resize drag. */
|
|
234
|
+
onResizePointerDown: (id: string, e: PointerEvent) => void;
|
|
239
235
|
}
|
|
240
236
|
/**
|
|
241
|
-
* React hook that manages
|
|
242
|
-
*
|
|
237
|
+
* React hook that manages draggable, resizable image overlays per spread and
|
|
238
|
+
* re-flows the text around them via `ChapterLayout.setImages`.
|
|
243
239
|
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* text reflow.
|
|
248
|
-
*
|
|
249
|
-
* @param layout - Current chapter layout (or `null` if not yet loaded).
|
|
250
|
-
* @param spreadIdx - Current spread index.
|
|
251
|
-
* @param onUpdate - Called with the updated {@link SpreadResult} after every reflow.
|
|
252
|
-
* @param options - Default dimensions and position for the overlay.
|
|
240
|
+
* @param layout - Chapter layout the overlays exclude text from, or `null` while none is ready.
|
|
241
|
+
* @param options - Current spread, overlay defaults, margin and reflow notification.
|
|
242
|
+
* @returns The overlay state, mutators and pointer handlers.
|
|
253
243
|
*
|
|
254
244
|
* @example
|
|
255
245
|
* ```tsx
|
|
256
|
-
* const
|
|
257
|
-
*
|
|
246
|
+
* const nav = useSpread(layout);
|
|
247
|
+
* const overlays = useImageOverlay(layout, {
|
|
248
|
+
* spreadIndex: nav.spreadIndex,
|
|
249
|
+
* onReflow: () => nav.refresh(),
|
|
250
|
+
* });
|
|
258
251
|
* ```
|
|
259
252
|
*/
|
|
260
|
-
declare function useImageOverlay(layout: ChapterLayout | null,
|
|
253
|
+
declare function useImageOverlay(layout: ChapterLayout | null, options: UseImageOverlayOptions): UseImageOverlayReturn;
|
|
261
254
|
|
|
262
|
-
/**
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Spread mode a view renders in once `'auto'` has been decided: one page at a
|
|
257
|
+
* time, or two-page spreads.
|
|
258
|
+
*/
|
|
259
|
+
type ResolvedSpreadMode = 'single' | 'double';
|
|
260
|
+
/** Options for {@link UseSpreadReturn.goTo}. */
|
|
261
|
+
interface GoToOptions {
|
|
262
|
+
/**
|
|
263
|
+
* Run the page-turn animation. With `false` the index changes immediately,
|
|
264
|
+
* cancelling any turn in flight — use it to restore a position after a
|
|
265
|
+
* re-layout, where an animated turn would briefly show the first spread.
|
|
266
|
+
* @defaultValue true
|
|
267
|
+
*/
|
|
268
|
+
animate?: boolean;
|
|
269
|
+
}
|
|
270
|
+
/** Options for {@link useSpread}. */
|
|
271
|
+
interface UseSpreadOptions {
|
|
272
|
+
/** Enable ArrowLeft/ArrowRight navigation. @defaultValue true */
|
|
273
|
+
enableKeyboard?: boolean;
|
|
274
|
+
/** Page-turn animation duration in milliseconds; `0` turns without animating. @defaultValue 180 */
|
|
275
|
+
turnDurationMs?: number;
|
|
276
|
+
/**
|
|
277
|
+
* Spread mode to navigate in. In `'single'` the navigation index counts
|
|
278
|
+
* pages; in `'double'` it counts two-page spreads. Changing it converts the
|
|
279
|
+
* index so the page on screen stays visible. @defaultValue 'double'
|
|
280
|
+
*/
|
|
281
|
+
spreadMode?: ResolvedSpreadMode;
|
|
282
|
+
/**
|
|
283
|
+
* Keep the visible text on screen when `layout` is replaced: the new layout
|
|
284
|
+
* opens at the position holding the first text the old one showed, instead
|
|
285
|
+
* of at index 0. @defaultValue false
|
|
286
|
+
*/
|
|
287
|
+
preservePosition?: boolean;
|
|
288
|
+
/**
|
|
289
|
+
* Called with the new navigation index after it changes: when an animated
|
|
290
|
+
* turn lands, at the end of {@link UseSpreadOptions.turnDurationMs}, or
|
|
291
|
+
* immediately for a turn without animation. Not called while a turn is in
|
|
292
|
+
* flight, and not called when a turn ends where it started.
|
|
293
|
+
*/
|
|
294
|
+
onIndexChange?: (index: number) => void;
|
|
295
|
+
}
|
|
296
|
+
/** Return value of {@link useSpread}. */
|
|
297
|
+
interface UseSpreadReturn {
|
|
298
|
+
/** Navigation index: a page index in single mode, a spread index otherwise. `0` without a layout. */
|
|
299
|
+
index: number;
|
|
300
|
+
/** Number of navigation positions: pages in single mode, spreads otherwise. `0` without a layout. */
|
|
301
|
+
count: number;
|
|
302
|
+
/** Index of the layout spread holding the visible page(s), as `ChapterLayout.getSpread` takes it. */
|
|
303
|
+
spreadIndex: number;
|
|
304
|
+
/** Number of spreads in the layout, whatever the spread mode. */
|
|
305
|
+
spreadCount: number;
|
|
306
|
+
/** Number of pages in the layout, as of {@link UseSpreadReturn.spread}. */
|
|
307
|
+
pageCount: number;
|
|
308
|
+
/** Layout spread holding the visible page(s), or `null` until the layout is ready. */
|
|
309
|
+
spread: SpreadResult | null;
|
|
310
|
+
/** Index of the first page shown, in reading order. */
|
|
311
|
+
firstPage: number;
|
|
312
|
+
/** Side of {@link UseSpreadReturn.spread} shown in single mode; `null` in double mode. */
|
|
313
|
+
singleSide: 'right' | 'left' | null;
|
|
314
|
+
/** Whether a page-turn animation is in flight. */
|
|
315
|
+
turning: boolean;
|
|
316
|
+
/** Move one position forward, counting from the target of a turn in flight. */
|
|
317
|
+
next: () => void;
|
|
318
|
+
/** Move one position back, counting from the target of a turn in flight. */
|
|
319
|
+
prev: () => void;
|
|
320
|
+
/**
|
|
321
|
+
* Go to a navigation index. Negative values go to `0` and values past the
|
|
322
|
+
* end to `count − 1`. A call during a turn replaces that turn's target, so
|
|
323
|
+
* the turn lands on the last index requested. A no-op without a layout or
|
|
324
|
+
* when `count` is `0`.
|
|
325
|
+
*
|
|
326
|
+
* @throws RangeError when `index` is not an integer (fractions, `NaN`, `±Infinity`).
|
|
327
|
+
*/
|
|
328
|
+
goTo: (index: number, options?: GoToOptions) => void;
|
|
329
|
+
/** Navigation index that shows the given page. */
|
|
330
|
+
indexOfPage: (pageIndex: number) => number;
|
|
331
|
+
/**
|
|
332
|
+
* Anchor at the start of the text shown at navigation index `index`. A page an
|
|
333
|
+
* image blocks entirely holds no text, so the anchor then comes from the next
|
|
334
|
+
* page that does, even past `index`; `null` when no page from there on holds text.
|
|
335
|
+
*/
|
|
336
|
+
anchorAt: (index: number) => InChapterAnchor | null;
|
|
337
|
+
/** Re-read {@link UseSpreadReturn.spread} from `layout` at the current index. */
|
|
338
|
+
refresh: () => void;
|
|
274
339
|
}
|
|
275
340
|
/**
|
|
276
|
-
*
|
|
277
|
-
*
|
|
341
|
+
* React hook that tracks the navigation position in a chapter layout and
|
|
342
|
+
* exposes navigation helpers with an optional page-turn animation.
|
|
343
|
+
*
|
|
344
|
+
* @param layout - Chapter layout to navigate, or `null` while none is ready.
|
|
345
|
+
* @param options - Spread mode, animation, keyboard and change notification.
|
|
346
|
+
* @returns The navigation state and helpers.
|
|
278
347
|
*/
|
|
279
|
-
declare function
|
|
348
|
+
declare function useSpread(layout: ChapterLayout | null, options?: UseSpreadOptions): UseSpreadReturn;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A selection rectangle from `ChapterLayout.selectionRects`, optionally
|
|
352
|
+
* carrying its own CSS fill colour.
|
|
353
|
+
*/
|
|
354
|
+
type SelectionRect = AnchorRect & {
|
|
355
|
+
/** CSS colour filling this rectangle; the stylesheet's selection fill when absent. */
|
|
356
|
+
color?: string;
|
|
357
|
+
};
|
|
358
|
+
/** The part of an {@link Annotation} a reader needs to draw it as a highlight. */
|
|
359
|
+
type ReaderAnnotation = Pick<Annotation, 'chapterIndex' | 'start' | 'end' | 'color'>;
|
|
360
|
+
/** Props for {@link MejiroSpread}; other `div` attributes go to the root element. */
|
|
361
|
+
interface MejiroSpreadProps extends ComponentPropsWithoutRef<'div'> {
|
|
362
|
+
/** Spread data to render. */
|
|
363
|
+
spread: SpreadResult;
|
|
364
|
+
/**
|
|
365
|
+
* Layout the spread comes from. When given, its `geometry` and `typography`
|
|
366
|
+
* supply every page-size and font prop left unset.
|
|
367
|
+
*/
|
|
368
|
+
layout?: ChapterLayout;
|
|
369
|
+
/** Page width (px). Defaults to `layout.geometry.pageWidth`. */
|
|
370
|
+
pageWidth?: number;
|
|
371
|
+
/** Page height (px). Defaults to `layout.geometry.pageHeight`. */
|
|
372
|
+
pageHeight?: number;
|
|
373
|
+
/** Content area height (px). Defaults to `layout.geometry.contentHeight`. */
|
|
374
|
+
contentHeight?: number;
|
|
375
|
+
/** CSS font family applied to the content. Defaults to `layout.typography.fontFamily`. */
|
|
376
|
+
fontFamily?: FontFamily;
|
|
377
|
+
/** Font size (px). Defaults to `layout.typography.fontSize`. */
|
|
378
|
+
fontSize?: number;
|
|
379
|
+
/** Line spacing multiplier. Defaults to `layout.typography.lineSpacing`. */
|
|
380
|
+
lineSpacing?: number;
|
|
381
|
+
/** Animate the page turn. */
|
|
382
|
+
turning?: boolean;
|
|
383
|
+
/** Header data for the right page. */
|
|
384
|
+
rightHeader?: PageHeaderData;
|
|
385
|
+
/** Header data for the left page. */
|
|
386
|
+
leftHeader?: PageHeaderData;
|
|
387
|
+
/**
|
|
388
|
+
* Image overlays on the current spread, relative to the right page. In
|
|
389
|
+
* single spread mode, only those whose centre lies on the page shown are drawn.
|
|
390
|
+
*/
|
|
391
|
+
images?: readonly MultiImageItem[];
|
|
392
|
+
/**
|
|
393
|
+
* Force slot-mode rendering on both pages. When omitted, each page falls
|
|
394
|
+
* through to {@link MejiroPageView}'s automatic choice: slot mode for pages
|
|
395
|
+
* with images, native `writing-mode: vertical-rl` otherwise.
|
|
396
|
+
*/
|
|
397
|
+
slotMode?: boolean;
|
|
398
|
+
/** Custom renderer for per-page headers. */
|
|
399
|
+
renderPageHeader?: (side: 'right' | 'left', header: PageHeaderData) => ReactNode;
|
|
400
|
+
/** Custom indicator placed inside the spread (e.g. {@link MejiroPageIndicator}). */
|
|
401
|
+
indicator?: ReactNode;
|
|
402
|
+
/** Called when the previous-page zone is clicked. */
|
|
403
|
+
onPrev?: () => void;
|
|
404
|
+
/** Called when the next-page zone is clicked. */
|
|
405
|
+
onNext?: () => void;
|
|
406
|
+
/** Pointer-down on an image overlay. */
|
|
407
|
+
onImagePointerDown?: (id: string, e: PointerEvent) => void;
|
|
408
|
+
/** Pointer-down on an image resize handle. */
|
|
409
|
+
onImageResizePointerDown?: (id: string, e: PointerEvent) => void;
|
|
410
|
+
/** Image overlay close button. */
|
|
411
|
+
onImageClose?: (id: string) => void;
|
|
412
|
+
/**
|
|
413
|
+
* Resolves a spread-local point to an in-chapter anchor.
|
|
414
|
+
* Typically `(point) => layout.anchorAtCoord(spreadIndex, point)`. When provided
|
|
415
|
+
* together with {@link MejiroSpreadProps.onSelectionChange}, the spread
|
|
416
|
+
* enables pointer-drag selection on the page content area.
|
|
417
|
+
*/
|
|
418
|
+
anchorAtCoord?: (point: SpreadPoint) => InChapterAnchor | null;
|
|
419
|
+
/**
|
|
420
|
+
* Zero-based index of the spread being rendered. Rectangles passed through
|
|
421
|
+
* {@link MejiroSpreadProps.selectionRects} carry spread-local coordinates,
|
|
422
|
+
* so this is what scopes them to this spread. When omitted, every supplied
|
|
423
|
+
* rectangle is painted.
|
|
424
|
+
*/
|
|
425
|
+
spreadIndex?: number;
|
|
426
|
+
/**
|
|
427
|
+
* Selection rectangles to render as a highlight overlay. Compute via
|
|
428
|
+
* {@link ChapterLayout.selectionRects}. Entries whose `spreadIndex` differs
|
|
429
|
+
* from {@link MejiroSpreadProps.spreadIndex} are ignored. An entry may carry
|
|
430
|
+
* a `color` that becomes that rectangle's fill.
|
|
431
|
+
*/
|
|
432
|
+
selectionRects?: readonly SelectionRect[];
|
|
433
|
+
/**
|
|
434
|
+
* Called when the user drags-selects text on the spread.
|
|
435
|
+
* Called with `null` on a single-click (caret) where start equals end.
|
|
436
|
+
*/
|
|
437
|
+
onSelectionChange?: (range: AnchorRange | null) => void;
|
|
438
|
+
/**
|
|
439
|
+
* `'single'` renders one page of the spread (centered), chosen by
|
|
440
|
+
* {@link MejiroSpreadProps.singleSide}; `'double'` renders both. Use
|
|
441
|
+
* `'single'` for portrait viewports or when a reader opts into single-page
|
|
442
|
+
* mode. @defaultValue 'double'
|
|
443
|
+
*/
|
|
444
|
+
spreadMode?: ResolvedSpreadMode;
|
|
445
|
+
/**
|
|
446
|
+
* Page of the spread shown in single spread mode, as `useSpread` reports it
|
|
447
|
+
* in `singleSide`; `null` (what `useSpread` reports in double mode) shows the
|
|
448
|
+
* right page. @defaultValue 'right'
|
|
449
|
+
*/
|
|
450
|
+
singleSide?: 'right' | 'left' | null;
|
|
451
|
+
/**
|
|
452
|
+
* Called when the user makes a quick swipe gesture on the spread.
|
|
453
|
+
* `direction === 'next'` means the user swiped from right to left (the
|
|
454
|
+
* natural direction in vertical-rl for advancing).
|
|
455
|
+
*/
|
|
456
|
+
onSwipe?: (direction: 'next' | 'prev') => void;
|
|
457
|
+
/** Called when the user taps the center area without swiping. */
|
|
458
|
+
onSurfaceTap?: () => void;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Renders a two-page spread (or one page of it in single spread mode) with the
|
|
462
|
+
* book frame, page chrome, navigation zones, and image overlays. Used inside
|
|
463
|
+
* `mejiro-reader-surface`.
|
|
464
|
+
*/
|
|
465
|
+
declare const MejiroSpread: react.ForwardRefExoticComponent<MejiroSpreadProps & react.RefAttributes<HTMLDivElement>>;
|
|
466
|
+
|
|
467
|
+
/** Second argument of a host `fetchEpub` callback. */
|
|
468
|
+
interface FetchEpubOptions {
|
|
469
|
+
/**
|
|
470
|
+
* Aborted when the load is superseded — by a newer load, a `url` change,
|
|
471
|
+
* `setEpub` or unmount. Pass it on to the request so the download stops too.
|
|
472
|
+
*/
|
|
473
|
+
signal: AbortSignal;
|
|
474
|
+
}
|
|
475
|
+
/** Options for {@link useEpub}. */
|
|
476
|
+
interface UseEpubOptions {
|
|
477
|
+
/**
|
|
478
|
+
* URL to load. Fetched on mount and again whenever it changes; clearing it
|
|
479
|
+
* abandons a load still in flight and keeps the current EPUB.
|
|
480
|
+
*/
|
|
481
|
+
url?: string;
|
|
482
|
+
/** Called after a successful load. */
|
|
483
|
+
onLoad?: (epub: EpubBook) => void;
|
|
484
|
+
/**
|
|
485
|
+
* Called when a load fails, including a non-2xx URL response
|
|
486
|
+
* (`MejiroError` `fetch-failed`). A `MejiroError` is passed as thrown.
|
|
487
|
+
*/
|
|
488
|
+
onError?: (error: Error) => void;
|
|
489
|
+
/**
|
|
490
|
+
* Extra options merged into the `fetch` call when loading by URL. Useful
|
|
491
|
+
* for sending bearer tokens or cookies (`credentials: 'include'`).
|
|
492
|
+
*/
|
|
493
|
+
fetchOptions?: RequestInit;
|
|
494
|
+
/**
|
|
495
|
+
* Custom EPUB fetcher used in place of the global `fetch`. Resolves to the
|
|
496
|
+
* raw bytes. Overrides {@link UseEpubOptions.fetchOptions} when set — common
|
|
497
|
+
* for hosts that already own an auth-aware HTTP client.
|
|
498
|
+
*/
|
|
499
|
+
fetchEpub?: (url: string, options: FetchEpubOptions) => Promise<BinaryInput>;
|
|
500
|
+
/**
|
|
501
|
+
* Archive resource limits applied while opening an EPUB. Raise them for
|
|
502
|
+
* trusted, image-heavy books; tighten them for a public drop zone. Omitted
|
|
503
|
+
* fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
|
|
504
|
+
*/
|
|
505
|
+
limits?: Partial<EpubParseLimits>;
|
|
506
|
+
}
|
|
507
|
+
/** Return value of {@link useEpub}. */
|
|
508
|
+
interface UseEpubReturn {
|
|
509
|
+
/** Current parsed EPUB, or `null` before any load. */
|
|
510
|
+
epub: EpubBook | null;
|
|
511
|
+
/** Whether a load is in progress. */
|
|
512
|
+
loading: boolean;
|
|
513
|
+
/** Last load error, if any. */
|
|
514
|
+
error: Error | null;
|
|
515
|
+
/**
|
|
516
|
+
* Parse from in-memory bytes. A `Uint8Array` is read through its own view
|
|
517
|
+
* and is neither retained nor modified.
|
|
518
|
+
*/
|
|
519
|
+
loadBuffer: (bytes: BinaryInput) => Promise<EpubBook | null>;
|
|
520
|
+
/** Parse from a {@link File}. */
|
|
521
|
+
loadFile: (file: File) => Promise<EpubBook | null>;
|
|
522
|
+
/** Fetch a URL and parse the response. */
|
|
523
|
+
loadUrl: (url: string) => Promise<EpubBook | null>;
|
|
524
|
+
/** Replace the current EPUB without going through the parser, abandoning a load in flight. */
|
|
525
|
+
setEpub: (epub: EpubBook | null) => void;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* React hook that parses EPUB files and exposes loading/error state plus
|
|
529
|
+
* convenience loaders for buffers, files, and URLs.
|
|
530
|
+
*
|
|
531
|
+
* One load runs at a time: starting another, changing `url`, calling
|
|
532
|
+
* `setEpub` or unmounting aborts the one in flight — its fetch and parse
|
|
533
|
+
* included — and its result is dropped. Each loader resolves to the parsed
|
|
534
|
+
* EPUB, or `null` when the load failed or was superseded.
|
|
535
|
+
*/
|
|
536
|
+
declare function useEpub(options?: UseEpubOptions): UseEpubReturn;
|
|
280
537
|
|
|
281
538
|
/**
|
|
282
539
|
* Where {@link MejiroReader} places its chapter navigation: the header
|
|
@@ -292,9 +549,9 @@ type MejiroReaderMode = 'paginated' | 'scroll';
|
|
|
292
549
|
/**
|
|
293
550
|
* Two-page vs single-page rendering of a spread.
|
|
294
551
|
* - `double` — always render two pages (default).
|
|
295
|
-
* - `single` — render one page at a time, centered
|
|
552
|
+
* - `single` — render one page at a time, centered.
|
|
296
553
|
* - `auto` — switch based on the surface aspect ratio (single when portrait),
|
|
297
|
-
*
|
|
554
|
+
* keeping the page on screen visible.
|
|
298
555
|
*/
|
|
299
556
|
type MejiroSpreadMode = 'double' | 'single' | 'auto';
|
|
300
557
|
|
|
@@ -320,60 +577,90 @@ type MejiroTheme = MejiroThemeName | {
|
|
|
320
577
|
name: MejiroThemeName;
|
|
321
578
|
override?: Record<string, string>;
|
|
322
579
|
};
|
|
323
|
-
/**
|
|
324
|
-
|
|
580
|
+
/**
|
|
581
|
+
* Spread-level position of a reader, as {@link MejiroReaderHandle.getSpreadPosition}
|
|
582
|
+
* reports it. A spread index does not survive a re-layout; persist a
|
|
583
|
+
* {@link ReadingAnchor} to keep a reading position.
|
|
584
|
+
*/
|
|
585
|
+
interface SpreadPosition {
|
|
325
586
|
/** Zero-based index of the current chapter. */
|
|
326
|
-
|
|
327
|
-
/** Zero-based index of the
|
|
328
|
-
|
|
329
|
-
/** Number of pages in the current chapter's layout. */
|
|
330
|
-
totalPages: number;
|
|
587
|
+
chapterIndex: number;
|
|
588
|
+
/** Zero-based index of the layout spread holding the visible page(s). */
|
|
589
|
+
spreadIndex: number;
|
|
331
590
|
/** Number of spreads in the current chapter's layout. */
|
|
332
|
-
|
|
591
|
+
spreadCount: number;
|
|
592
|
+
/** Number of pages in the current chapter's layout. */
|
|
593
|
+
pageCount: number;
|
|
594
|
+
}
|
|
595
|
+
/** Payload of the `spreadIndexChange` reader event. */
|
|
596
|
+
interface MejiroReaderSpreadIndexChangeEvent {
|
|
597
|
+
/** Chapter the spread belongs to. */
|
|
598
|
+
chapterIndex: number;
|
|
599
|
+
/** Layout spread now shown. */
|
|
600
|
+
spreadIndex: number;
|
|
601
|
+
}
|
|
602
|
+
/** Payload of the `chapterFinished` reader event. */
|
|
603
|
+
interface MejiroReaderChapterFinishedEvent {
|
|
604
|
+
/** Chapter whose last position was reached. */
|
|
605
|
+
chapterIndex: number;
|
|
606
|
+
}
|
|
607
|
+
/** Payload of the `turnStart` reader event. */
|
|
608
|
+
interface MejiroReaderTurnStartEvent {
|
|
609
|
+
/** Navigation position the turn leaves: a page in single mode, a spread otherwise. */
|
|
610
|
+
from: number;
|
|
611
|
+
}
|
|
612
|
+
/** Payload of the `turnEnd` reader event. */
|
|
613
|
+
interface MejiroReaderTurnEndEvent {
|
|
614
|
+
/** Navigation position the turn landed on: a page in single mode, a spread otherwise. */
|
|
615
|
+
to: number;
|
|
616
|
+
}
|
|
617
|
+
/** Half-open range of reading anchors, as {@link MejiroReaderHandle.getVisibleRange} returns it. */
|
|
618
|
+
interface ReadingAnchorRange {
|
|
619
|
+
/** First visible position (inclusive). */
|
|
620
|
+
start: ReadingAnchor;
|
|
621
|
+
/** Position where the text after the visible range begins (exclusive). */
|
|
622
|
+
end: ReadingAnchor;
|
|
333
623
|
}
|
|
334
624
|
/**
|
|
335
625
|
* Event payloads emitted by {@link MejiroReaderHandle.subscribe}.
|
|
336
626
|
*
|
|
337
|
-
* Each property maps an event name to its listener signature.
|
|
627
|
+
* Each property maps an event name to its listener signature. An event that
|
|
628
|
+
* has a prop twin is named after it without the `on` prefix.
|
|
338
629
|
*/
|
|
339
630
|
interface MejiroReaderEventMap {
|
|
340
|
-
/** Fires
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}) => void;
|
|
349
|
-
/** Fires after a turn animation completes (the new spread is now shown). */
|
|
350
|
-
turnEnd: (payload: {
|
|
351
|
-
to: number;
|
|
352
|
-
}) => void;
|
|
353
|
-
/** Fires when the reader reaches the last spread of the current chapter. */
|
|
354
|
-
chapterFinished: (payload: {
|
|
355
|
-
chapter: number;
|
|
356
|
-
}) => void;
|
|
631
|
+
/** Fires once the reader shows another layout spread or chapter. */
|
|
632
|
+
spreadIndexChange: (payload: MejiroReaderSpreadIndexChangeEvent) => void;
|
|
633
|
+
/** Fires when a turn animation begins (before the new position is shown). */
|
|
634
|
+
turnStart: (payload: MejiroReaderTurnStartEvent) => void;
|
|
635
|
+
/** Fires after a turn animation completes (the new position is now shown). */
|
|
636
|
+
turnEnd: (payload: MejiroReaderTurnEndEvent) => void;
|
|
637
|
+
/** Fires when the reader reaches the last position of the current chapter. */
|
|
638
|
+
chapterFinished: (payload: MejiroReaderChapterFinishedEvent) => void;
|
|
357
639
|
}
|
|
358
640
|
/** Imperative handle returned by `ref={...}` on {@link MejiroReader}. */
|
|
359
641
|
interface MejiroReaderHandle {
|
|
360
|
-
/**
|
|
361
|
-
|
|
362
|
-
|
|
642
|
+
/**
|
|
643
|
+
* Turns to a layout spread (0-based, clamped to the chapter's spreads). In
|
|
644
|
+
* single-page mode the spread opens on its right page.
|
|
645
|
+
*
|
|
646
|
+
* @throws RangeError when `spreadIndex` is not an integer.
|
|
647
|
+
*/
|
|
648
|
+
goToSpread(spreadIndex: number): void;
|
|
649
|
+
/** Advance one position: a page in single-page mode, a spread otherwise. */
|
|
363
650
|
next(): void;
|
|
364
|
-
/** Go back one
|
|
651
|
+
/** Go back one position. */
|
|
365
652
|
prev(): void;
|
|
366
|
-
/** Jump to a chapter (clamped to the book's chapters;
|
|
367
|
-
goToChapter(
|
|
368
|
-
/**
|
|
369
|
-
|
|
653
|
+
/** Jump to a chapter (clamped to the book's chapters; opens at its first spread). */
|
|
654
|
+
goToChapter(chapterIndex: number): void;
|
|
655
|
+
/** Reads the current spread-level position. */
|
|
656
|
+
getSpreadPosition(): SpreadPosition;
|
|
370
657
|
/**
|
|
371
658
|
* Navigate to a {@link ReadingAnchor}. If the chapter differs from the
|
|
372
659
|
* current one, the chapter is switched first; once the new layout is ready
|
|
373
|
-
* the anchor is resolved and the matching
|
|
660
|
+
* the anchor is resolved and the matching position is opened. A call made
|
|
374
661
|
* before the book has loaded is applied once it has.
|
|
375
662
|
*
|
|
376
|
-
* Returns a promise that resolves once the
|
|
663
|
+
* Returns a promise that resolves once the position has been applied, or
|
|
377
664
|
* without moving when the anchor's chapter or position does not exist in the
|
|
378
665
|
* book. If another `goToAnchor` is invoked before the previous one settles,
|
|
379
666
|
* the earlier promise resolves immediately (superseded). Resolves on unmount.
|
|
@@ -381,31 +668,28 @@ interface MejiroReaderHandle {
|
|
|
381
668
|
goToAnchor(anchor: ReadingAnchor): Promise<void>;
|
|
382
669
|
/**
|
|
383
670
|
* Returns the {@link ReadingAnchor} at the start of the text on the current
|
|
384
|
-
*
|
|
385
|
-
* page
|
|
386
|
-
*
|
|
671
|
+
* position, or `null` if the layout is not ready. When an image blocks every
|
|
672
|
+
* page shown, the anchor is where the text resumes after it; `null` again if
|
|
673
|
+
* none follows.
|
|
387
674
|
*/
|
|
388
675
|
getAnchor(): ReadingAnchor | null;
|
|
389
676
|
/**
|
|
390
677
|
* Returns the half-open range of {@link ReadingAnchor}s visible on the
|
|
391
|
-
* current
|
|
392
|
-
* that has any (or the end of the chapter when none does).
|
|
678
|
+
* current position. `end` points at the start of the text on the next
|
|
679
|
+
* position that has any (or the end of the chapter when none does).
|
|
393
680
|
*/
|
|
394
|
-
getVisibleRange():
|
|
395
|
-
start: ReadingAnchor;
|
|
396
|
-
end: ReadingAnchor;
|
|
397
|
-
} | null;
|
|
681
|
+
getVisibleRange(): ReadingAnchorRange | null;
|
|
398
682
|
/**
|
|
399
|
-
*
|
|
400
|
-
*
|
|
683
|
+
* Merges `patch` into the book options at runtime; font / size changes
|
|
684
|
+
* re-measure and re-layout asynchronously.
|
|
401
685
|
*
|
|
402
686
|
* Successive calls are coalesced into a single application; the returned
|
|
403
687
|
* promise resolves once that application has settled. A failed application
|
|
404
688
|
* (such as a font that measures as a fallback under `strictFontCheck`) is
|
|
405
|
-
* reported through {@link
|
|
406
|
-
* the promise.
|
|
689
|
+
* reported through {@link MejiroReaderCommonProps.onError} rather than
|
|
690
|
+
* rejecting the promise.
|
|
407
691
|
*/
|
|
408
|
-
|
|
692
|
+
updateOptions(patch: BookOptionsPatch): Promise<void>;
|
|
409
693
|
/**
|
|
410
694
|
* Subscribes to a reader lifecycle event. Returns a function that
|
|
411
695
|
* detaches the listener.
|
|
@@ -422,51 +706,89 @@ interface MejiroReaderHandle {
|
|
|
422
706
|
interface MejiroReaderSettingsSlot {
|
|
423
707
|
/** Current effective settings (font, size, line spacing, kinsoku, hanging). */
|
|
424
708
|
settings: EditableSettings;
|
|
425
|
-
/**
|
|
426
|
-
update: (
|
|
709
|
+
/** Merges a settings change into the book options and re-flows the chapter. */
|
|
710
|
+
update: (patch: BookOptionsPatch) => void;
|
|
427
711
|
/** Whether the settings panel is currently open. */
|
|
428
712
|
open: boolean;
|
|
429
713
|
/** Toggles the settings panel open/closed (same as the header button). */
|
|
430
714
|
toggle: () => void;
|
|
431
715
|
}
|
|
432
|
-
/**
|
|
716
|
+
/**
|
|
717
|
+
* Props shared across every {@link MejiroReader} source mode.
|
|
718
|
+
*
|
|
719
|
+
* The position props come in value / handler pairs (`chapterIndex` /
|
|
720
|
+
* `onChapterIndexChange`, `spreadIndex` / `onSpreadIndexChange`, `anchor` /
|
|
721
|
+
* `onAnchorChange`). A value without its handler is the initial position; with
|
|
722
|
+
* its handler the pair is controlled: the reader reports each navigation
|
|
723
|
+
* through the handler and shows the value it is given, returning to it when
|
|
724
|
+
* the host keeps it unchanged (an absent index reads as 0). When `anchor` is
|
|
725
|
+
* given it decides the chapter and spread, and `chapterIndex` / `spreadIndex`
|
|
726
|
+
* are not read.
|
|
727
|
+
*/
|
|
433
728
|
interface MejiroReaderCommonProps {
|
|
434
729
|
/**
|
|
435
|
-
*
|
|
436
|
-
* (`serif` 16px, line spacing 1.8, strict kinsoku, hanging punctuation on)
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
* ```ts
|
|
440
|
-
* { ...DEFAULT_BOOK_OPTIONS, fontFamily: '"Noto Serif JP"', fontSize: 18 }
|
|
441
|
-
* ```
|
|
730
|
+
* Book options. Optional — defaults to {@link DEFAULT_BOOK_OPTIONS}
|
|
731
|
+
* (`serif` 16px, line spacing 1.8, strict kinsoku, hanging punctuation on);
|
|
732
|
+
* the keys given here override those defaults.
|
|
442
733
|
*
|
|
443
|
-
* `
|
|
734
|
+
* The keys `MejiroBook.updateOptions` accepts follow this prop by content;
|
|
735
|
+
* the construction-only keys (`strictFontCheck`, `analyzer`, …) are read
|
|
736
|
+
* once, when the reader mounts.
|
|
444
737
|
*/
|
|
445
|
-
options?: Partial<
|
|
738
|
+
options?: Partial<BookOptions>;
|
|
446
739
|
/**
|
|
447
|
-
* Page-geometry overrides forwarded to `MejiroBook.
|
|
740
|
+
* Page-geometry overrides forwarded to `MejiroBook.fitPageSize`. Use to
|
|
448
741
|
* tune how the spread is sized inside the surface — most usefully to shrink
|
|
449
742
|
* the reserved margins so the pages fill their frame, e.g.
|
|
450
743
|
* `pageGeometry={{ gutterOffset: 0, headerOffset: 0 }}`. Also accepts
|
|
451
|
-
* `aspect`, `minWidth`, `minHeight`, `maxHeight`, and
|
|
452
|
-
* fields fall back to the built-in defaults.
|
|
744
|
+
* `aspect`, `minWidth`, `minHeight`, `maxHeight`, and the page padding;
|
|
745
|
+
* omitted fields fall back to the built-in defaults.
|
|
453
746
|
*/
|
|
454
|
-
pageGeometry?:
|
|
747
|
+
pageGeometry?: FitPageSizeOptions;
|
|
455
748
|
/** Font choices for the settings panel. */
|
|
456
|
-
fonts?: FontChoice[];
|
|
749
|
+
fonts?: readonly FontChoice[];
|
|
750
|
+
/**
|
|
751
|
+
* Chapter to show. The initial chapter unless
|
|
752
|
+
* {@link MejiroReaderCommonProps.onChapterIndexChange} is given, which
|
|
753
|
+
* makes it controlled. An uncontrolled chapter resets to 0 when the book
|
|
754
|
+
* changes. @defaultValue 0
|
|
755
|
+
*/
|
|
756
|
+
chapterIndex?: number;
|
|
757
|
+
/**
|
|
758
|
+
* Called with the chapter the reader moves to. Passing it makes
|
|
759
|
+
* {@link MejiroReaderCommonProps.chapterIndex} controlled.
|
|
760
|
+
*/
|
|
761
|
+
onChapterIndexChange?: (chapterIndex: number) => void;
|
|
762
|
+
/**
|
|
763
|
+
* Layout spread to show — always a spread of the chapter layout, also in
|
|
764
|
+
* single-page mode, where the spread opens on its right page (the first in
|
|
765
|
+
* reading order). The initial spread unless
|
|
766
|
+
* {@link MejiroReaderCommonProps.onSpreadIndexChange} is given, which makes
|
|
767
|
+
* it controlled. A spread index does not survive a re-layout; use `anchor`
|
|
768
|
+
* to keep a reading position. @defaultValue 0
|
|
769
|
+
*/
|
|
770
|
+
spreadIndex?: number;
|
|
457
771
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
772
|
+
* Called with the layout spread the reader moves to. Turning from the right
|
|
773
|
+
* to the left page of one spread in single-page mode keeps the spread, so it
|
|
774
|
+
* does not fire; follow `onAnchorChange` for page-level changes. Passing it
|
|
775
|
+
* makes {@link MejiroReaderCommonProps.spreadIndex} controlled.
|
|
460
776
|
*/
|
|
461
|
-
|
|
777
|
+
onSpreadIndexChange?: (spreadIndex: number) => void;
|
|
462
778
|
/**
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* `getAnchor` / `goToAnchor` instead.
|
|
779
|
+
* Reading position to show. When given, it decides the chapter and spread
|
|
780
|
+
* and `chapterIndex` / `spreadIndex` are not read. The initial position
|
|
781
|
+
* unless {@link MejiroReaderCommonProps.onAnchorChange} is given, which
|
|
782
|
+
* makes it controlled.
|
|
468
783
|
*/
|
|
469
|
-
|
|
784
|
+
anchor?: ReadingAnchor | null;
|
|
785
|
+
/**
|
|
786
|
+
* Called with the anchor at the start of the text the reader moves to, on
|
|
787
|
+
* each move of the visible page(s) or chapter. Passing it makes
|
|
788
|
+
* {@link MejiroReaderCommonProps.anchor} controlled. Pair with
|
|
789
|
+
* `useReadingPosition` to persist the position.
|
|
790
|
+
*/
|
|
791
|
+
onAnchorChange?: (anchor: ReadingAnchor) => void;
|
|
470
792
|
/**
|
|
471
793
|
* Visual theme preset, or `{ name, override }` to layer custom
|
|
472
794
|
* CSS variables on top of a preset. @defaultValue 'light'
|
|
@@ -482,9 +804,8 @@ interface MejiroReaderCommonProps {
|
|
|
482
804
|
mode?: MejiroReaderMode;
|
|
483
805
|
/**
|
|
484
806
|
* Spread layout. `double` (default) renders two pages; `single` renders one
|
|
485
|
-
* page at a time
|
|
486
|
-
*
|
|
487
|
-
* viewports, keeping the page on screen visible.
|
|
807
|
+
* page at a time; `auto` flips to `single` for portrait viewports, keeping
|
|
808
|
+
* the page on screen visible.
|
|
488
809
|
*/
|
|
489
810
|
spreadMode?: MejiroSpreadMode;
|
|
490
811
|
/**
|
|
@@ -494,7 +815,7 @@ interface MejiroReaderCommonProps {
|
|
|
494
815
|
* embedding host only has to constrain the width (no height/aspect magic
|
|
495
816
|
* numbers, no letterbox). In `width` mode the reserved `gutterOffset` /
|
|
496
817
|
* `headerOffset` default to 0 so the spread fills edge-to-edge; override via
|
|
497
|
-
* {@link
|
|
818
|
+
* {@link MejiroReaderCommonProps.pageGeometry} if you still want them. @defaultValue 'fill'
|
|
498
819
|
*/
|
|
499
820
|
fit?: MejiroReaderFit;
|
|
500
821
|
/**
|
|
@@ -523,10 +844,12 @@ interface MejiroReaderCommonProps {
|
|
|
523
844
|
*/
|
|
524
845
|
limits?: Partial<EpubParseLimits>;
|
|
525
846
|
/**
|
|
526
|
-
* Custom EPUB fetcher used in place of the global `fetch
|
|
527
|
-
*
|
|
847
|
+
* Custom EPUB fetcher used in place of the global `fetch`; resolves to the
|
|
848
|
+
* raw bytes. `options.signal` aborts when the load is superseded or the
|
|
849
|
+
* reader unmounts. Overrides {@link MejiroReaderCommonProps.fetchOptions}
|
|
850
|
+
* when set.
|
|
528
851
|
*/
|
|
529
|
-
fetchEpub?: (url: string) => Promise<
|
|
852
|
+
fetchEpub?: (url: string, options: FetchEpubOptions) => Promise<BinaryInput>;
|
|
530
853
|
/**
|
|
531
854
|
* Built-in locale for UI strings (`'en'` / `'ja'`). Pair with `messages`
|
|
532
855
|
* to override individual strings. Defaults to the nearest `MejiroI18nProvider`
|
|
@@ -539,26 +862,19 @@ interface MejiroReaderCommonProps {
|
|
|
539
862
|
* without re-implementing every label.
|
|
540
863
|
*/
|
|
541
864
|
messages?: Partial<MejiroMessages>;
|
|
542
|
-
/**
|
|
865
|
+
/**
|
|
866
|
+
* Header title text. The header — chapter select, stats, Open / Image /
|
|
867
|
+
* Settings buttons — is drawn only when a title or a
|
|
868
|
+
* {@link MejiroReaderCommonProps.logo} is given.
|
|
869
|
+
*/
|
|
543
870
|
title?: string;
|
|
544
|
-
/** Header subtitle. @defaultValue `messages.logoSubtitle` */
|
|
871
|
+
/** Header subtitle, shown under the title. @defaultValue `messages.logoSubtitle` */
|
|
545
872
|
subtitle?: string;
|
|
546
873
|
/**
|
|
547
|
-
*
|
|
548
|
-
* the
|
|
549
|
-
* header, use `enableHeader={false}`.
|
|
874
|
+
* Header slot replacing the default logo block (title + subtitle). Giving
|
|
875
|
+
* it draws the header; pass `null` to draw the header without a logo.
|
|
550
876
|
*/
|
|
551
877
|
logo?: ReactNode;
|
|
552
|
-
/**
|
|
553
|
-
* Shorthand for a chrome-less reader. When `true`, the defaults for
|
|
554
|
-
* `enableHeader`, `enableChapterNav`, `enableSettings`, `enableStats`, and
|
|
555
|
-
* `enablePageIndicator` flip from `true` to `false`. Explicitly-passed
|
|
556
|
-
* enable* props still win, so you can opt parts back in.
|
|
557
|
-
* @defaultValue false
|
|
558
|
-
*/
|
|
559
|
-
bare?: boolean;
|
|
560
|
-
/** Show the built-in header. @defaultValue `!bare` */
|
|
561
|
-
enableHeader?: boolean;
|
|
562
878
|
/**
|
|
563
879
|
* Show the drop zone affordance. SaaS-style readers should keep this off
|
|
564
880
|
* (the host controls which EPUB is delivered); set true to accept
|
|
@@ -566,90 +882,85 @@ interface MejiroReaderCommonProps {
|
|
|
566
882
|
* @defaultValue false
|
|
567
883
|
*/
|
|
568
884
|
enableDropZone?: boolean;
|
|
569
|
-
/** Show the chapter selector in the header. @defaultValue `!bare` */
|
|
570
|
-
enableChapterNav?: boolean;
|
|
571
885
|
/**
|
|
572
|
-
* Where to render the built-in chapter navigation
|
|
886
|
+
* Where to render the built-in chapter navigation; `'none'` renders
|
|
887
|
+
* neither. The `'select'` dropdown sits in the header.
|
|
573
888
|
* @defaultValue 'select'
|
|
574
889
|
*/
|
|
575
890
|
chapterNavMode?: MejiroChapterNavMode;
|
|
576
|
-
/**
|
|
577
|
-
|
|
891
|
+
/**
|
|
892
|
+
* Show the settings panel and its header toggle. @defaultValue true
|
|
893
|
+
*/
|
|
894
|
+
showSettings?: boolean;
|
|
578
895
|
/**
|
|
579
896
|
* Replaces the built-in settings controls with custom UI while keeping the
|
|
580
897
|
* panel chrome and its open/close accordion. Receives a
|
|
581
898
|
* {@link MejiroReaderSettingsSlot} wired to the live reader, so a host can
|
|
582
899
|
* build its own settings form without a parallel `options` shadow. The header
|
|
583
|
-
* "Settings" button still toggles the panel. `
|
|
900
|
+
* "Settings" button still toggles the panel. `showSettings` remains the
|
|
584
901
|
* on/off switch.
|
|
585
902
|
*/
|
|
586
903
|
renderSettings?: (slot: MejiroReaderSettingsSlot) => ReactNode;
|
|
587
|
-
/** Show the image
|
|
588
|
-
|
|
589
|
-
/** Show the
|
|
590
|
-
|
|
591
|
-
/**
|
|
904
|
+
/** Show the header button that places a sample image overlay. @defaultValue false */
|
|
905
|
+
showImageOverlayButton?: boolean;
|
|
906
|
+
/** Show the layout statistics in the header. @defaultValue false */
|
|
907
|
+
showStats?: boolean;
|
|
908
|
+
/**
|
|
909
|
+
* Bind ArrowLeft / ArrowRight to navigation while focus is inside the
|
|
910
|
+
* reader. The reader root takes focus for this. @defaultValue true
|
|
911
|
+
*/
|
|
592
912
|
enableKeyboard?: boolean;
|
|
593
|
-
/** Show the "n / total" indicator. @defaultValue
|
|
594
|
-
|
|
913
|
+
/** Show the "n / total" indicator. @defaultValue true */
|
|
914
|
+
showPageIndicator?: boolean;
|
|
595
915
|
/**
|
|
596
916
|
* Which page of a spread shows its page number in the running head.
|
|
597
917
|
* `'both'` numbers each page (right = odd, left = even), `'right'` /
|
|
598
918
|
* `'left'` number only that side, `'none'` hides them (the
|
|
599
|
-
* {@link
|
|
919
|
+
* {@link MejiroReaderCommonProps.showPageIndicator} "n / total" badge is
|
|
600
920
|
* independent). @defaultValue 'both'
|
|
601
921
|
*/
|
|
602
922
|
pageNumbers?: PageNumberDisplay;
|
|
603
923
|
/**
|
|
604
924
|
* Reader-side annotations to render as highlights. Each annotation whose
|
|
605
|
-
* `
|
|
925
|
+
* `chapterIndex` matches the current chapter is converted to spread-local
|
|
606
926
|
* rectangles via `ChapterLayout.selectionRects`; the rectangles landing on
|
|
607
927
|
* the spread on screen are drawn on top of the page content. Pair with
|
|
608
|
-
* {@link useAnnotations} for persistence
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
annotations?: ReadonlyArray<{
|
|
612
|
-
chapter: number;
|
|
613
|
-
start: InChapterAnchor;
|
|
614
|
-
end: InChapterAnchor;
|
|
615
|
-
color?: string;
|
|
616
|
-
}>;
|
|
928
|
+
* {@link useAnnotations} for persistence.
|
|
929
|
+
*/
|
|
930
|
+
annotations?: readonly ReaderAnnotation[];
|
|
617
931
|
/** Called after a successful EPUB load. */
|
|
618
|
-
onLoad?: (
|
|
932
|
+
onLoad?: (epub: EpubBook) => void;
|
|
619
933
|
/**
|
|
620
934
|
* Called when loading or parsing an EPUB fails, and when applying an option
|
|
621
935
|
* change fails (such as a font that measures as a fallback under
|
|
622
936
|
* `strictFontCheck`; without it, a font that fails to load is not an error).
|
|
623
937
|
*/
|
|
624
938
|
onError?: (error: Error) => void;
|
|
625
|
-
/**
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
/** Called when the spread index changes — pair with the `spreadIdx` prop for controlled use. */
|
|
630
|
-
onSpreadIdxChange?: (spreadIdx: number) => void;
|
|
631
|
-
/**
|
|
632
|
-
* Called when the reader moves from one spread to another within the shown
|
|
633
|
-
* book (a change of chapter or spread index, like `spreadChanged`). Receives
|
|
634
|
-
* the anchor of the spread that was just left and the dwell time in
|
|
939
|
+
/**
|
|
940
|
+
* Called when the reader moves from one position to another within the
|
|
941
|
+
* shown book (a change of chapter or navigation position). Receives the
|
|
942
|
+
* anchor of the position that was just left and the dwell time in
|
|
635
943
|
* milliseconds (computed via `performance.now()`). A book swap and unmount
|
|
636
|
-
* do not report the
|
|
944
|
+
* do not report the position being left. Useful for engagement analytics.
|
|
637
945
|
*/
|
|
638
946
|
onPageRead?: (anchor: ReadingAnchor, dwellMs: number) => void;
|
|
639
947
|
/**
|
|
640
|
-
* Called when the reader reaches the last
|
|
641
|
-
* trigger as the `chapterFinished` event on
|
|
948
|
+
* Called with the chapter index when the reader reaches the last position
|
|
949
|
+
* of a chapter. Same trigger as the `chapterFinished` event on
|
|
950
|
+
* {@link MejiroReaderHandle.subscribe}.
|
|
642
951
|
*/
|
|
643
|
-
|
|
952
|
+
onChapterFinished?: (chapterIndex: number) => void;
|
|
644
953
|
}
|
|
645
954
|
/**
|
|
646
|
-
*
|
|
647
|
-
*
|
|
955
|
+
* Parsed-source variant: render a pre-parsed `EpubBook`. Pass `null` to
|
|
956
|
+
* render an empty reader (e.g. while the book is still loading on the host).
|
|
648
957
|
*/
|
|
649
|
-
interface
|
|
958
|
+
interface MejiroReaderParsedProps extends MejiroReaderCommonProps {
|
|
650
959
|
/** Pre-parsed EPUB. Cannot be combined with `epubUrl` / `manuscript`. */
|
|
651
960
|
epub: EpubBook | null;
|
|
961
|
+
/** Not accepted alongside `epub`. */
|
|
652
962
|
epubUrl?: never;
|
|
963
|
+
/** Not accepted alongside `epub`. */
|
|
653
964
|
manuscript?: never;
|
|
654
965
|
}
|
|
655
966
|
/**
|
|
@@ -657,19 +968,24 @@ interface MejiroReaderControlledProps extends MejiroReaderCommonProps {
|
|
|
657
968
|
* Use this for "just open this book" scenarios.
|
|
658
969
|
*/
|
|
659
970
|
interface MejiroReaderUrlProps extends MejiroReaderCommonProps {
|
|
660
|
-
/** EPUB URL fetched on mount. Cannot be combined with `epub` / `manuscript`. */
|
|
971
|
+
/** EPUB URL, fetched on mount and whenever it changes. Cannot be combined with `epub` / `manuscript`. */
|
|
661
972
|
epubUrl: string;
|
|
973
|
+
/** Not accepted alongside `epubUrl`. */
|
|
662
974
|
epub?: never;
|
|
975
|
+
/** Not accepted alongside `epubUrl`. */
|
|
663
976
|
manuscript?: never;
|
|
664
977
|
}
|
|
665
978
|
/**
|
|
666
|
-
*
|
|
979
|
+
* Picker-source variant: the reader exposes its drop zone / file picker.
|
|
667
980
|
* Neither `epub` nor `epubUrl` is supplied — useful for free-form viewers
|
|
668
981
|
* that accept user-supplied books.
|
|
669
982
|
*/
|
|
670
|
-
interface
|
|
983
|
+
interface MejiroReaderPickerProps extends MejiroReaderCommonProps {
|
|
984
|
+
/** Not accepted by the picker source. */
|
|
671
985
|
epub?: never;
|
|
986
|
+
/** Not accepted by the picker source. */
|
|
672
987
|
epubUrl?: never;
|
|
988
|
+
/** Not accepted by the picker source. */
|
|
673
989
|
manuscript?: never;
|
|
674
990
|
}
|
|
675
991
|
/**
|
|
@@ -683,30 +999,30 @@ interface MejiroReaderManuscriptProps extends MejiroReaderCommonProps {
|
|
|
683
999
|
manuscript: readonly ManuscriptChapter[];
|
|
684
1000
|
/** Manuscript notation dialect. @defaultValue `'mejiro'` */
|
|
685
1001
|
dialect?: ManuscriptDialect;
|
|
1002
|
+
/** Not accepted alongside `manuscript`. */
|
|
686
1003
|
epub?: never;
|
|
1004
|
+
/** Not accepted alongside `manuscript`. */
|
|
687
1005
|
epubUrl?: never;
|
|
688
1006
|
}
|
|
689
1007
|
/**
|
|
690
1008
|
* Props for {@link MejiroReader}. Discriminated union of the four source
|
|
691
1009
|
* modes — TypeScript prevents passing more than one source at once.
|
|
692
1010
|
*/
|
|
693
|
-
type MejiroReaderProps =
|
|
1011
|
+
type MejiroReaderProps = MejiroReaderParsedProps | MejiroReaderUrlProps | MejiroReaderPickerProps | MejiroReaderManuscriptProps;
|
|
694
1012
|
/**
|
|
695
1013
|
* Full-page EPUB reader. Composes the package's primitives into a working
|
|
696
|
-
* reader
|
|
697
|
-
*
|
|
1014
|
+
* reader: the header (drawn when a `title` or `logo` is given), chapter
|
|
1015
|
+
* navigation, settings, page indicator and keyboard navigation scoped to the
|
|
1016
|
+
* reader root. The `ref` exposes {@link MejiroReaderHandle} for imperative
|
|
1017
|
+
* navigation.
|
|
1018
|
+
*
|
|
1019
|
+
* ```tsx
|
|
1020
|
+
* const reader = useRef<MejiroReaderHandle>(null);
|
|
1021
|
+
* reader.current?.goToSpread(12);
|
|
1022
|
+
* ```
|
|
698
1023
|
*/
|
|
699
1024
|
declare const MejiroReader: react.ForwardRefExoticComponent<MejiroReaderProps & react.RefAttributes<MejiroReaderHandle>>;
|
|
700
1025
|
|
|
701
|
-
/** One chapter of the manuscript being edited. */
|
|
702
|
-
interface ManuscriptEditorChapter {
|
|
703
|
-
/** Stable identifier; survives reordering and title edits. */
|
|
704
|
-
id: string;
|
|
705
|
-
/** Chapter title; an empty title falls back to the localized "untitled" label. */
|
|
706
|
-
title: string;
|
|
707
|
-
/** Chapter body in the editor's manuscript notation. */
|
|
708
|
-
body: string;
|
|
709
|
-
}
|
|
710
1026
|
/** Autosave payload emitted by {@link MejiroManuscriptEditor}. */
|
|
711
1027
|
interface ManuscriptAutosaveDraft {
|
|
712
1028
|
/** Book title as currently entered. */
|
|
@@ -716,53 +1032,18 @@ interface ManuscriptAutosaveDraft {
|
|
|
716
1032
|
/** Selected cover image, or `null` when none is set. */
|
|
717
1033
|
cover: File | null;
|
|
718
1034
|
/** Chapters in reading order, as plain (non-reactive) copies. */
|
|
719
|
-
chapters:
|
|
1035
|
+
chapters: readonly ManuscriptChapter$1[];
|
|
720
1036
|
}
|
|
721
1037
|
/**
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
* supplied here.
|
|
1038
|
+
* The {@link MejiroReader} props an editor forwards to its live preview. The
|
|
1039
|
+
* book, the chapter and its change handler, `fonts` and `onError` are driven
|
|
1040
|
+
* by the editor itself.
|
|
726
1041
|
*/
|
|
727
|
-
|
|
728
|
-
/** Header subtitle of the preview reader. */
|
|
729
|
-
subtitle?: string;
|
|
730
|
-
/** Header title of the preview reader. */
|
|
731
|
-
title?: string;
|
|
732
|
-
/** Where the preview places its chapter navigation. @defaultValue 'panel' */
|
|
733
|
-
chapterNavMode?: 'select' | 'panel' | 'both' | 'none';
|
|
734
|
-
/** Show the preview header. */
|
|
735
|
-
enableHeader?: boolean;
|
|
736
|
-
/** Show the preview chapter navigation. */
|
|
737
|
-
enableChapterNav?: boolean;
|
|
738
|
-
/** Show the preview settings panel toggle. */
|
|
739
|
-
enableSettings?: boolean;
|
|
740
|
-
/** Show the preview layout statistics. */
|
|
741
|
-
enableStats?: boolean;
|
|
742
|
-
/** Enable arrow-key page turns in the preview. */
|
|
743
|
-
enableKeyboard?: boolean;
|
|
744
|
-
/** Show the preview page indicator. */
|
|
745
|
-
enablePageIndicator?: boolean;
|
|
746
|
-
/** Book options forwarded to the embedded reader preview. */
|
|
747
|
-
options?: Partial<BookOptions>;
|
|
748
|
-
/** Theme forwarded to the embedded reader preview. */
|
|
749
|
-
theme?: MejiroTheme;
|
|
750
|
-
/** Custom settings controls forwarded to the embedded reader preview. */
|
|
751
|
-
renderSettings?: (slot: MejiroReaderSettingsSlot) => ReactNode;
|
|
752
|
-
/**
|
|
753
|
-
* Toggle the surface-tap chrome-hide behavior of the embedded reader.
|
|
754
|
-
* Defaults to `false` here (the editor's preview is part of a side-by-side
|
|
755
|
-
* authoring workflow where tap-to-hide would surprise the author). Set
|
|
756
|
-
* to `true` to demo the fullscreen-reader behavior.
|
|
757
|
-
*/
|
|
758
|
-
enableSurfaceTap?: boolean;
|
|
759
|
-
/** Render the preview without any reader chrome. */
|
|
760
|
-
bare?: boolean;
|
|
761
|
-
}
|
|
1042
|
+
type ManuscriptPreviewProps = Pick<MejiroReaderCommonProps, 'title' | 'subtitle' | 'logo' | 'theme' | 'options' | 'pageGeometry' | 'mode' | 'spreadMode' | 'fit' | 'chapterNavMode' | 'pageNumbers' | 'showSettings' | 'renderSettings' | 'showStats' | 'showPageIndicator' | 'enableKeyboard' | 'enableSurfaceTap' | 'locale' | 'messages' | 'fallback'>;
|
|
762
1043
|
/** Props for {@link MejiroManuscriptEditor}. */
|
|
763
1044
|
interface MejiroManuscriptEditorProps {
|
|
764
1045
|
/** Font choices passed to the preview reader. */
|
|
765
|
-
fonts?: FontChoice[];
|
|
1046
|
+
fonts?: readonly FontChoice[];
|
|
766
1047
|
/**
|
|
767
1048
|
* Title. When `onTitleChange` is supplied, this is the controlled value
|
|
768
1049
|
* (changes propagate from parent to the input). Otherwise it is the
|
|
@@ -785,8 +1066,17 @@ interface MejiroManuscriptEditorProps {
|
|
|
785
1066
|
cover?: File | null;
|
|
786
1067
|
/** Called whenever the cover changes. Enables controlled mode. */
|
|
787
1068
|
onCoverChange?: (cover: File | null) => void;
|
|
788
|
-
/**
|
|
789
|
-
|
|
1069
|
+
/**
|
|
1070
|
+
* Chapters. Controlled when `onChaptersChange` is supplied; otherwise the
|
|
1071
|
+
* initial chapters. Without any, the editor starts with one chapter titled
|
|
1072
|
+
* and filled from the active message catalog.
|
|
1073
|
+
*/
|
|
1074
|
+
chapters?: readonly ManuscriptChapter$1[];
|
|
1075
|
+
/**
|
|
1076
|
+
* Called with the whole chapter list after each chapter edit, addition,
|
|
1077
|
+
* removal or reorder. Enables controlled mode for `chapters`.
|
|
1078
|
+
*/
|
|
1079
|
+
onChaptersChange?: (chapters: readonly ManuscriptChapter$1[]) => void;
|
|
790
1080
|
/**
|
|
791
1081
|
* Manuscript notation dialect. Drives the notation highlighter, the live
|
|
792
1082
|
* preview, and the exported EPUB alike, so the whole editor interprets one
|
|
@@ -794,17 +1084,16 @@ interface MejiroManuscriptEditorProps {
|
|
|
794
1084
|
*/
|
|
795
1085
|
dialect?: ManuscriptDialect;
|
|
796
1086
|
/**
|
|
797
|
-
* Called whenever the
|
|
798
|
-
* {@link MejiroManuscriptEditorProps.
|
|
799
|
-
* to localStorage, IndexedDB, or upload to a server.
|
|
1087
|
+
* Called whenever the draft settles (debounced by
|
|
1088
|
+
* {@link MejiroManuscriptEditorProps.autosaveDebounceMs}). Use to persist
|
|
1089
|
+
* drafts to localStorage, IndexedDB, or upload to a server.
|
|
800
1090
|
*/
|
|
801
1091
|
onAutosave?: (draft: ManuscriptAutosaveDraft) => void | Promise<void>;
|
|
802
1092
|
/** Autosave debounce in milliseconds. @defaultValue 800 */
|
|
803
|
-
|
|
1093
|
+
autosaveDebounceMs?: number;
|
|
804
1094
|
/**
|
|
805
|
-
* Props forwarded to the embedded {@link MejiroReader} preview.
|
|
806
|
-
*
|
|
807
|
-
* `chapter`, and `onChapterChange` remain driven by the editor.
|
|
1095
|
+
* Props forwarded to the embedded {@link MejiroReader} preview. The preview
|
|
1096
|
+
* header shows the work's title unless `title` is given here.
|
|
808
1097
|
*/
|
|
809
1098
|
previewProps?: ManuscriptPreviewProps;
|
|
810
1099
|
/**
|
|
@@ -815,8 +1104,8 @@ interface MejiroManuscriptEditorProps {
|
|
|
815
1104
|
* references that must be fetched at export time.
|
|
816
1105
|
*/
|
|
817
1106
|
assetResolver?: AssetResolver;
|
|
818
|
-
/** Called
|
|
819
|
-
onExport?: (
|
|
1107
|
+
/** Called with the exported bytes, before the download. */
|
|
1108
|
+
onExport?: (bytes: Uint8Array<ArrayBuffer>) => void;
|
|
820
1109
|
/**
|
|
821
1110
|
* Called when the EPUB export fails (asset resolution, cover reading, or
|
|
822
1111
|
* packaging) or the preview reader fails. The same error is shown in the editor panel, so hosts only
|
|
@@ -831,14 +1120,138 @@ interface MejiroManuscriptEditorProps {
|
|
|
831
1120
|
panelSide?: 'left' | 'right';
|
|
832
1121
|
}
|
|
833
1122
|
/** Manuscript-to-EPUB editor for author drafts from posting sites. */
|
|
834
|
-
declare function MejiroManuscriptEditor({ fonts, title: titleProp, onTitleChange, author: authorProp, onAuthorChange, cover: coverProp, onCoverChange, chapters:
|
|
1123
|
+
declare function MejiroManuscriptEditor({ fonts, title: titleProp, onTitleChange, author: authorProp, onAuthorChange, cover: coverProp, onCoverChange, chapters: chaptersProp, onChaptersChange, dialect, onAutosave, autosaveDebounceMs, previewProps, assetResolver, onExport, onError, panelSide, }: MejiroManuscriptEditorProps): ReactNode;
|
|
1124
|
+
|
|
1125
|
+
/** Props for {@link MejiroEditor}. */
|
|
1126
|
+
interface MejiroEditorProps {
|
|
1127
|
+
/** EPUB URL, loaded on mount and whenever it changes. */
|
|
1128
|
+
epubUrl?: string;
|
|
1129
|
+
/**
|
|
1130
|
+
* Extra options merged into the `fetch` call that loads `epubUrl`. Useful
|
|
1131
|
+
* for sending bearer tokens or cookies (`credentials: 'include'`).
|
|
1132
|
+
*/
|
|
1133
|
+
fetchOptions?: RequestInit;
|
|
1134
|
+
/**
|
|
1135
|
+
* Custom EPUB fetcher used in place of the global `fetch`; resolves to the
|
|
1136
|
+
* raw bytes. `options.signal` aborts when the load is superseded or the
|
|
1137
|
+
* editor unmounts. Overrides {@link MejiroEditorProps.fetchOptions} when set.
|
|
1138
|
+
*/
|
|
1139
|
+
fetchEpub?: (url: string, options: FetchEpubOptions) => Promise<BinaryInput>;
|
|
1140
|
+
/** Font choices passed to the preview reader. */
|
|
1141
|
+
fonts?: readonly FontChoice[];
|
|
1142
|
+
/**
|
|
1143
|
+
* Allow editing paragraph text (the "Proofread" section). When `false` and
|
|
1144
|
+
* `enableRuby` is on, the paragraph text stays visible read-only so a ruby
|
|
1145
|
+
* base range can still be selected.
|
|
1146
|
+
* @defaultValue true
|
|
1147
|
+
*/
|
|
1148
|
+
enableProofread?: boolean;
|
|
1149
|
+
/**
|
|
1150
|
+
* Allow editing ruby annotations (the "Ruby" section).
|
|
1151
|
+
* @defaultValue true
|
|
1152
|
+
*/
|
|
1153
|
+
enableRuby?: boolean;
|
|
1154
|
+
/**
|
|
1155
|
+
* Allow inserting images into the EPUB (the "Images" section).
|
|
1156
|
+
* @defaultValue true
|
|
1157
|
+
*/
|
|
1158
|
+
enableImages?: boolean;
|
|
1159
|
+
/**
|
|
1160
|
+
* Show the export button. SaaS publishers can hide it to restrict downloads
|
|
1161
|
+
* (e.g. server-side export only).
|
|
1162
|
+
* @defaultValue true
|
|
1163
|
+
*/
|
|
1164
|
+
showExportButton?: boolean;
|
|
1165
|
+
/** What the export button produces and whether it is offered as a download. */
|
|
1166
|
+
exportPolicy?: ExportPolicy;
|
|
1167
|
+
/**
|
|
1168
|
+
* Resolves URL-only image assets (`url` set, `data` unset) into bytes at
|
|
1169
|
+
* export time. Forwarded to `editor.export()`. Use this to keep large image
|
|
1170
|
+
* bytes off the client during editing and only fetch them once when the
|
|
1171
|
+
* EPUB is assembled — e.g. signed S3 URLs that require custom auth headers.
|
|
1172
|
+
*/
|
|
1173
|
+
assetResolver?: AssetResolver;
|
|
1174
|
+
/**
|
|
1175
|
+
* Archive resource limits applied while opening an EPUB. Raise them for
|
|
1176
|
+
* trusted, image-heavy books; tighten them for a public drop zone. Omitted
|
|
1177
|
+
* fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
|
|
1178
|
+
*/
|
|
1179
|
+
limits?: Partial<EpubParseLimits>;
|
|
1180
|
+
/**
|
|
1181
|
+
* Props forwarded to the embedded {@link MejiroReader} preview (theme,
|
|
1182
|
+
* options, chrome). The book, the chapter and its change handler, `fonts`
|
|
1183
|
+
* and `onError` remain driven by the editor.
|
|
1184
|
+
*/
|
|
1185
|
+
previewProps?: ManuscriptPreviewProps;
|
|
1186
|
+
/** Called after an EPUB is loaded into the editor. */
|
|
1187
|
+
onLoad?: (editor: EditableEpub) => void;
|
|
1188
|
+
/** Called with the exported bytes, after `exportPolicy.transform`, before any download. */
|
|
1189
|
+
onExport?: (bytes: Uint8Array<ArrayBuffer>) => void;
|
|
1190
|
+
/**
|
|
1191
|
+
* Called when loading, image insertion, export or the preview reader fails.
|
|
1192
|
+
* The error is also shown in the editor until a later load, image insertion
|
|
1193
|
+
* or export succeeds.
|
|
1194
|
+
*/
|
|
1195
|
+
onError?: (error: Error) => void;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Restrictions on what {@link MejiroEditor}'s export produces. Applied in
|
|
1199
|
+
* this order: `watermark` (written into the exported copy only, never into the
|
|
1200
|
+
* edited document) → `transform` (replaces the bytes with its result) →
|
|
1201
|
+
* `download`.
|
|
1202
|
+
*/
|
|
1203
|
+
interface ExportPolicy {
|
|
1204
|
+
/**
|
|
1205
|
+
* Offer the exported bytes as a browser download. With `false` the bytes are
|
|
1206
|
+
* still produced and `onExport` still fires — use it to ship the bytes
|
|
1207
|
+
* elsewhere (e.g. uploading to a backend).
|
|
1208
|
+
* @defaultValue true
|
|
1209
|
+
*/
|
|
1210
|
+
download?: boolean;
|
|
1211
|
+
/**
|
|
1212
|
+
* Transforms the exported bytes before `onExport` and the download.
|
|
1213
|
+
* Typically a server round-trip that returns a DRM-wrapped EPUB.
|
|
1214
|
+
*/
|
|
1215
|
+
transform?: (bytes: Uint8Array<ArrayBuffer>) => Uint8Array<ArrayBuffer> | Promise<Uint8Array<ArrayBuffer>>;
|
|
1216
|
+
/**
|
|
1217
|
+
* Visible watermark text. Each exported chapter starts with a paragraph
|
|
1218
|
+
* holding it after a `[mejiro-watermark]` prefix, so a downstream renderer
|
|
1219
|
+
* can theme it by that prefix. An empty string adds nothing.
|
|
1220
|
+
*/
|
|
1221
|
+
watermark?: string;
|
|
1222
|
+
}
|
|
1223
|
+
/** EPUB editor UI for proofreading, ruby edits, image insertion, and export. */
|
|
1224
|
+
declare function MejiroEditor({ epubUrl, fetchOptions, fetchEpub, fonts, enableProofread, enableRuby, enableImages, showExportButton, exportPolicy, assetResolver, limits, previewProps, onLoad, onExport, onError, }: MejiroEditorProps): ReactNode;
|
|
1225
|
+
|
|
1226
|
+
/** Props for {@link MejiroImagePlaceholder}; other `div` attributes go to the root element. */
|
|
1227
|
+
interface MejiroImagePlaceholderProps extends ComponentPropsWithoutRef<'div'> {
|
|
1228
|
+
/** Position and size of the placeholder (px). */
|
|
1229
|
+
rect: ImageOverlayRect;
|
|
1230
|
+
/** Label inside the placeholder. @defaultValue `messages.imageButton` */
|
|
1231
|
+
label?: string;
|
|
1232
|
+
/** Pointer-down on the body (drag). */
|
|
1233
|
+
onOverlayPointerDown?: (e: PointerEvent) => void;
|
|
1234
|
+
/** Pointer-down on the resize handle. */
|
|
1235
|
+
onResizePointerDown?: (e: PointerEvent) => void;
|
|
1236
|
+
/** Triggered when the close button is pressed. */
|
|
1237
|
+
onClose?: () => void;
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Decorative image placeholder with drag and resize affordances, drawn where
|
|
1241
|
+
* an image overlay excludes text. Pair the pointer handlers with
|
|
1242
|
+
* {@link useImageOverlay}.
|
|
1243
|
+
*/
|
|
1244
|
+
declare const MejiroImagePlaceholder: react.ForwardRefExoticComponent<MejiroImagePlaceholderProps & react.RefAttributes<HTMLDivElement>>;
|
|
835
1245
|
|
|
836
|
-
/**
|
|
837
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* Props for {@link MejiroNotationHighlighter}; other `textarea` attributes,
|
|
1248
|
+
* the native `onChange` included, go to the textarea.
|
|
1249
|
+
*/
|
|
1250
|
+
interface MejiroNotationHighlighterProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'value'> {
|
|
838
1251
|
/** Source manuscript text. */
|
|
839
1252
|
value: string;
|
|
840
|
-
/** Called whenever the textarea content changes. */
|
|
841
|
-
|
|
1253
|
+
/** Called with the new text whenever the textarea content changes, and when an IME composition ends. */
|
|
1254
|
+
onValueChange: (next: string) => void;
|
|
842
1255
|
/** Manuscript notation dialect. @defaultValue `'mejiro'` */
|
|
843
1256
|
dialect?: ManuscriptDialect;
|
|
844
1257
|
/** Class applied to the wrapper element. */
|
|
@@ -859,8 +1272,8 @@ interface MejiroNotationHighlighterProps extends Omit<TextareaHTMLAttributes<HTM
|
|
|
859
1272
|
*/
|
|
860
1273
|
declare const MejiroNotationHighlighter: react.ForwardRefExoticComponent<MejiroNotationHighlighterProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
861
1274
|
|
|
862
|
-
/** Props for the MejiroPage component. */
|
|
863
|
-
interface MejiroPageProps {
|
|
1275
|
+
/** Props for the MejiroPage component; other `div` attributes go to the root element. */
|
|
1276
|
+
interface MejiroPageProps extends ComponentPropsWithoutRef<'div'> {
|
|
864
1277
|
/** Render page data from `buildRenderPage()`. */
|
|
865
1278
|
page: RenderPage;
|
|
866
1279
|
/** Additional CSS class name for the root element. */
|
|
@@ -874,25 +1287,36 @@ interface MejiroPageProps {
|
|
|
874
1287
|
* Converts a `RenderPage` data structure into DOM elements using
|
|
875
1288
|
* `mejiro-` prefixed CSS classes for layout.
|
|
876
1289
|
*/
|
|
877
|
-
declare
|
|
1290
|
+
declare const MejiroPage: react.ForwardRefExoticComponent<MejiroPageProps & react.RefAttributes<HTMLDivElement>>;
|
|
878
1291
|
|
|
879
|
-
/** Props for {@link MejiroPageIndicator}. */
|
|
880
|
-
interface MejiroPageIndicatorProps {
|
|
881
|
-
/**
|
|
882
|
-
|
|
883
|
-
/**
|
|
884
|
-
|
|
1292
|
+
/** Props for {@link MejiroPageIndicator}; other `div` attributes go to the root element. */
|
|
1293
|
+
interface MejiroPageIndicatorProps extends ComponentPropsWithoutRef<'div'> {
|
|
1294
|
+
/** Zero-based navigation index, as `useSpread` reports it in `index`. Shown one-based. */
|
|
1295
|
+
index: number;
|
|
1296
|
+
/** Number of navigation positions, as `useSpread` reports it in `count`. */
|
|
1297
|
+
count: number;
|
|
885
1298
|
}
|
|
886
|
-
/** Displays
|
|
887
|
-
declare
|
|
1299
|
+
/** Displays the one-based position out of the total, e.g. `3 / 12`, under the book. */
|
|
1300
|
+
declare const MejiroPageIndicator: react.ForwardRefExoticComponent<MejiroPageIndicatorProps & react.RefAttributes<HTMLDivElement>>;
|
|
888
1301
|
|
|
889
|
-
/** Props for the MejiroPageView component. */
|
|
890
|
-
interface MejiroPageViewProps {
|
|
1302
|
+
/** Props for the MejiroPageView component; other `div` attributes go to the root element. */
|
|
1303
|
+
interface MejiroPageViewProps extends ComponentPropsWithoutRef<'div'> {
|
|
891
1304
|
/** Page result from {@link ChapterLayout.getSpread} or {@link ChapterLayout.getPage}. */
|
|
892
1305
|
result: PageResult;
|
|
893
|
-
/**
|
|
1306
|
+
/**
|
|
1307
|
+
* Layout the page comes from. When given, its `typography` supplies
|
|
1308
|
+
* `fontFamily` and `lineSpacing` when they are left unset.
|
|
1309
|
+
*/
|
|
1310
|
+
layout?: ChapterLayout;
|
|
1311
|
+
/**
|
|
1312
|
+
* CSS font family for slot-based rendering (used when images are present).
|
|
1313
|
+
* Defaults to `layout.typography.fontFamily`.
|
|
1314
|
+
*/
|
|
894
1315
|
fontFamily?: FontFamily;
|
|
895
|
-
/**
|
|
1316
|
+
/**
|
|
1317
|
+
* Line spacing multiplier for slot-based rendering (used when images are
|
|
1318
|
+
* present). Defaults to `layout.typography.lineSpacing`.
|
|
1319
|
+
*/
|
|
896
1320
|
lineSpacing?: number;
|
|
897
1321
|
/**
|
|
898
1322
|
* Force slot-based rendering even when `result.hasImages` is false.
|
|
@@ -918,77 +1342,26 @@ interface MejiroPageViewProps {
|
|
|
918
1342
|
* <MejiroPageView result={spread.right} fontFamily="serif" lineSpacing={1.8} />
|
|
919
1343
|
* ```
|
|
920
1344
|
*/
|
|
921
|
-
declare
|
|
1345
|
+
declare const MejiroPageView: react.ForwardRefExoticComponent<MejiroPageViewProps & react.RefAttributes<HTMLDivElement>>;
|
|
922
1346
|
|
|
923
|
-
/**
|
|
924
|
-
interface
|
|
925
|
-
/** Stable ID for the overlay (auto-assigned on add). */
|
|
926
|
-
id: string;
|
|
927
|
-
/** Position and size in pixels, relative to the right page. */
|
|
928
|
-
rect: ImageRect;
|
|
929
|
-
}
|
|
930
|
-
/** Options for {@link useMultiImageOverlay}. */
|
|
931
|
-
interface UseMultiImageOverlayOptions {
|
|
932
|
-
/** Default image width. @defaultValue 120 */
|
|
933
|
-
defaultWidth?: number;
|
|
934
|
-
/** Default image height. @defaultValue 160 */
|
|
935
|
-
defaultHeight?: number;
|
|
936
|
-
/** Default x. @defaultValue 80 */
|
|
937
|
-
defaultX?: number;
|
|
938
|
-
/** Default y. @defaultValue 100 */
|
|
939
|
-
defaultY?: number;
|
|
940
|
-
/** Margin around each image, in pixels. Defaults to the book's font size. */
|
|
941
|
-
margin?: number;
|
|
942
|
-
/** Called after every reflow caused by adding/removing/moving an image. */
|
|
943
|
-
onUpdate?: (spread: SpreadResult) => void;
|
|
944
|
-
}
|
|
945
|
-
/** Return value of {@link useMultiImageOverlay}. */
|
|
946
|
-
interface UseMultiImageOverlayReturn {
|
|
1347
|
+
/** Props for {@link MejiroScrollView}; other `div` attributes go to the scroll container. */
|
|
1348
|
+
interface MejiroScrollViewProps extends ComponentPropsWithoutRef<'div'> {
|
|
947
1349
|
/**
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
* before any view renders from it, so this map and the layout together key
|
|
951
|
-
* anything derived from the layout.
|
|
1350
|
+
* Layout containing the pages to render. Its `geometry` and `typography`
|
|
1351
|
+
* supply every page-size and font prop left unset.
|
|
952
1352
|
*/
|
|
953
|
-
imagesBySpread: Map<number, MultiImageItem[]>;
|
|
954
|
-
/** Images on the current spread; a new array whenever `imagesBySpread` changes. */
|
|
955
|
-
currentImages: MultiImageItem[];
|
|
956
|
-
/** Whether any spread has at least one image. */
|
|
957
|
-
hasImages: boolean;
|
|
958
|
-
/** Add a new image on the current spread. */
|
|
959
|
-
addImage: (overrides?: Partial<ImageRect>) => MultiImageItem;
|
|
960
|
-
/** Remove the image with the given id. */
|
|
961
|
-
removeImage: (id: string) => void;
|
|
962
|
-
/** Replace an image's rectangle. */
|
|
963
|
-
updateImage: (id: string, rect: Partial<ImageRect>) => void;
|
|
964
|
-
/** Remove every image (or only those on `spreadIdx` if given). */
|
|
965
|
-
clearImages: (spreadIdx?: number) => void;
|
|
966
|
-
/** Pointer-down handler for the overlay body (drag). */
|
|
967
|
-
onOverlayPointerDown: (id: string, e: PointerEvent) => void;
|
|
968
|
-
/** Pointer-down handler for the resize handle. */
|
|
969
|
-
onResizePointerDown: (id: string, e: PointerEvent) => void;
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* React hook that manages multiple draggable/resizable image overlays
|
|
973
|
-
* per spread with automatic reflow via {@link ChapterLayout.setImages}.
|
|
974
|
-
*/
|
|
975
|
-
declare function useMultiImageOverlay(layout: ChapterLayout | null, spreadIdx: number, options?: UseMultiImageOverlayOptions): UseMultiImageOverlayReturn;
|
|
976
|
-
|
|
977
|
-
/** Props for {@link MejiroScrollView}. */
|
|
978
|
-
interface MejiroScrollViewProps {
|
|
979
|
-
/** Layout containing the pages to render. */
|
|
980
1353
|
layout: ChapterLayout;
|
|
981
|
-
/** Page width in px. */
|
|
982
|
-
pageWidth
|
|
983
|
-
/** Page height in px. */
|
|
984
|
-
pageHeight
|
|
985
|
-
/** Content area height (px). */
|
|
986
|
-
contentHeight
|
|
987
|
-
/** CSS font family applied to the content. */
|
|
1354
|
+
/** Page width in px. Defaults to `layout.geometry.pageWidth`. */
|
|
1355
|
+
pageWidth?: number;
|
|
1356
|
+
/** Page height in px. Defaults to `layout.geometry.pageHeight`. */
|
|
1357
|
+
pageHeight?: number;
|
|
1358
|
+
/** Content area height (px). Defaults to `layout.geometry.contentHeight`. */
|
|
1359
|
+
contentHeight?: number;
|
|
1360
|
+
/** CSS font family applied to the content. Defaults to `layout.typography.fontFamily`. */
|
|
988
1361
|
fontFamily?: FontFamily;
|
|
989
|
-
/** Font size
|
|
1362
|
+
/** Font size (px). Defaults to `layout.typography.fontSize`. */
|
|
990
1363
|
fontSize?: number;
|
|
991
|
-
/** Line spacing multiplier. */
|
|
1364
|
+
/** Line spacing multiplier. Defaults to `layout.typography.lineSpacing`. */
|
|
992
1365
|
lineSpacing?: number;
|
|
993
1366
|
/** Force slot-based rendering on every page. */
|
|
994
1367
|
slotMode?: boolean;
|
|
@@ -996,7 +1369,7 @@ interface MejiroScrollViewProps {
|
|
|
996
1369
|
* Visible page index reported to the parent as the user scrolls. The page
|
|
997
1370
|
* with the largest intersection with the viewport is treated as visible.
|
|
998
1371
|
*/
|
|
999
|
-
onVisiblePageChange?: (
|
|
1372
|
+
onVisiblePageChange?: (pageIndex: number, source: 'user' | 'programmatic') => void;
|
|
1000
1373
|
/**
|
|
1001
1374
|
* Target page to scroll into view. When set, the view scrolls so that the
|
|
1002
1375
|
* matching page sits at the top of the scroll container.
|
|
@@ -1007,22 +1380,20 @@ interface MejiroScrollViewProps {
|
|
|
1007
1380
|
/**
|
|
1008
1381
|
* Selection rectangles to highlight. Compute via
|
|
1009
1382
|
* {@link ChapterLayout.selectionRects}; each entry is painted on the page its
|
|
1010
|
-
* `
|
|
1383
|
+
* `pageIndex` addresses. An entry may carry a `color` fill.
|
|
1011
1384
|
*/
|
|
1012
|
-
selectionRects?: readonly
|
|
1013
|
-
color?: string;
|
|
1014
|
-
})[];
|
|
1385
|
+
selectionRects?: readonly SelectionRect[];
|
|
1015
1386
|
/** Zero-based spread whose pages carry {@link MejiroScrollViewProps.images}. */
|
|
1016
|
-
|
|
1387
|
+
spreadIndex?: number;
|
|
1017
1388
|
/**
|
|
1018
|
-
* Image overlays on the spread at {@link MejiroScrollViewProps.
|
|
1389
|
+
* Image overlays on the spread at {@link MejiroScrollViewProps.spreadIndex}.
|
|
1019
1390
|
* Each renders on the page whose area contains its centre (see
|
|
1020
1391
|
* `overlayPageSide`), matching {@link MejiroSpread}'s single-page routing.
|
|
1021
1392
|
* The layout reflows in place when its images change, so a new array here is
|
|
1022
|
-
* also what re-reads the pages; `
|
|
1393
|
+
* also what re-reads the pages; `useImageOverlay`'s `currentImages`
|
|
1023
1394
|
* provides one on every change.
|
|
1024
1395
|
*/
|
|
1025
|
-
images?: MultiImageItem[];
|
|
1396
|
+
images?: readonly MultiImageItem[];
|
|
1026
1397
|
/**
|
|
1027
1398
|
* Which pages print their page number in the running head, by the same rule
|
|
1028
1399
|
* as the paginated reader. @defaultValue 'both'
|
|
@@ -1041,10 +1412,10 @@ interface MejiroScrollViewProps {
|
|
|
1041
1412
|
* detected via `IntersectionObserver` and reported through
|
|
1042
1413
|
* {@link MejiroScrollViewProps.onVisiblePageChange}.
|
|
1043
1414
|
*/
|
|
1044
|
-
declare
|
|
1415
|
+
declare const MejiroScrollView: react.ForwardRefExoticComponent<MejiroScrollViewProps & react.RefAttributes<HTMLDivElement>>;
|
|
1045
1416
|
|
|
1046
|
-
/** Props for {@link MejiroSelectionLayer}. */
|
|
1047
|
-
interface MejiroSelectionLayerProps {
|
|
1417
|
+
/** Props for {@link MejiroSelectionLayer}; other `div` attributes go to the root element. */
|
|
1418
|
+
interface MejiroSelectionLayerProps extends ComponentPropsWithoutRef<'div'> {
|
|
1048
1419
|
/**
|
|
1049
1420
|
* Spread-local rectangles to highlight. Compute these via
|
|
1050
1421
|
* {@link ChapterLayout.selectionRects} and pass the full array; the layer
|
|
@@ -1054,9 +1425,7 @@ interface MejiroSelectionLayerProps {
|
|
|
1054
1425
|
* fill. Entries without one take the fill from the shipped stylesheet
|
|
1055
1426
|
* (`.mejiro-selection-rect`, themeable via `--mejiro-selection-bg`).
|
|
1056
1427
|
*/
|
|
1057
|
-
rects: readonly
|
|
1058
|
-
color?: string;
|
|
1059
|
-
})[];
|
|
1428
|
+
rects: readonly SelectionRect[];
|
|
1060
1429
|
/** Which page-side this layer is rendered into. */
|
|
1061
1430
|
side: 'right' | 'left';
|
|
1062
1431
|
/** Optional class added to the outer wrapper. */
|
|
@@ -1069,289 +1438,144 @@ interface MejiroSelectionLayerProps {
|
|
|
1069
1438
|
rectStyle?: CSSProperties;
|
|
1070
1439
|
}
|
|
1071
1440
|
/**
|
|
1072
|
-
* Renders a selection-highlight overlay inside a page-content container.
|
|
1073
|
-
*
|
|
1074
|
-
* Use as a child of `.mejiro-reader-page-clip` (or any element that shares the
|
|
1075
|
-
* page's content coordinate frame). The layer is pointer-transparent so it
|
|
1076
|
-
* does not interfere with selection drag on the page below.
|
|
1077
|
-
*/
|
|
1078
|
-
declare
|
|
1079
|
-
|
|
1080
|
-
/** A single volume in a multi-book library. */
|
|
1081
|
-
interface VolumeInfo<T = unknown> {
|
|
1082
|
-
/** Stable identifier (e.g. ISBN, slug, internal ID). */
|
|
1083
|
-
id: string;
|
|
1084
|
-
/** Human-readable title shown in pickers. */
|
|
1085
|
-
label: string;
|
|
1086
|
-
/** Optional author / byline. */
|
|
1087
|
-
author?: string;
|
|
1088
|
-
/** Optional cover image URL. */
|
|
1089
|
-
cover?: string;
|
|
1090
|
-
/** Free-form metadata attached by the host. */
|
|
1091
|
-
meta?: T;
|
|
1092
|
-
}
|
|
1093
|
-
/** Options for {@link useLibrary}. */
|
|
1094
|
-
interface UseLibraryOptions<T = unknown> {
|
|
1095
|
-
/** The volumes available to the reader. */
|
|
1096
|
-
volumes: readonly VolumeInfo<T>[];
|
|
1097
|
-
/** ID of the volume to start on. Defaults to the first entry. */
|
|
1098
|
-
initialVolumeId?: string;
|
|
1099
|
-
/** Called
|
|
1100
|
-
|
|
1101
|
-
}
|
|
1102
|
-
/** Return value of {@link useLibrary}. */
|
|
1103
|
-
interface UseLibraryReturn<T = unknown> {
|
|
1104
|
-
/** The list of volumes (same reference as the options input). */
|
|
1105
|
-
list: readonly VolumeInfo<T>[];
|
|
1106
|
-
/** Currently active volume, or `null` for an empty library. */
|
|
1107
|
-
|
|
1108
|
-
/** Index of the
|
|
1109
|
-
|
|
1110
|
-
/** Advance to the next volume in the list (no-op at the end). */
|
|
1111
|
-
next(): void;
|
|
1112
|
-
/** Go back to the previous volume in the list (no-op at the start). */
|
|
1113
|
-
prev(): void;
|
|
1114
|
-
/**
|
|
1115
|
-
|
|
1116
|
-
}
|
|
1117
|
-
/**
|
|
1118
|
-
* Headless hook for managing a multi-volume reading session. Pair it with
|
|
1119
|
-
* {@link MejiroReader} (driving its `epub` / `epubUrl` prop) or
|
|
1120
|
-
* {@link MejiroShelf} (visual picker).
|
|
1121
|
-
*/
|
|
1122
|
-
declare function useLibrary<T = unknown>(options: UseLibraryOptions<T>): UseLibraryReturn<T>;
|
|
1123
|
-
|
|
1124
|
-
/**
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
/** Props for {@link MejiroSpread}. */
|
|
1142
|
-
interface MejiroSpreadProps {
|
|
1143
|
-
/** Spread data to render. */
|
|
1144
|
-
spread: SpreadResult;
|
|
1145
|
-
/** Page width (px). */
|
|
1146
|
-
pageWidth: number;
|
|
1147
|
-
/** Page height (px). */
|
|
1148
|
-
pageHeight: number;
|
|
1149
|
-
/** Content area height (px). */
|
|
1150
|
-
contentHeight: number;
|
|
1151
|
-
/** CSS font family applied to the content. */
|
|
1152
|
-
fontFamily?: FontFamily;
|
|
1153
|
-
/** Font size override (px). */
|
|
1154
|
-
fontSize?: number;
|
|
1155
|
-
/** Line spacing multiplier (slot mode). */
|
|
1156
|
-
lineSpacing?: number;
|
|
1157
|
-
/** Animate the page turn. */
|
|
1158
|
-
turning?: boolean;
|
|
1159
|
-
/** Header data for the right page. */
|
|
1160
|
-
rightHeader?: PageHeaderData;
|
|
1161
|
-
/** Header data for the left page. */
|
|
1162
|
-
leftHeader?: PageHeaderData;
|
|
1163
|
-
/**
|
|
1164
|
-
* Image overlays on the current spread, relative to the right page. With
|
|
1165
|
-
* {@link MejiroSpreadProps.singlePage}, only those whose centre lies on the
|
|
1166
|
-
* page shown are drawn.
|
|
1167
|
-
*/
|
|
1168
|
-
images?: MultiImageItem[];
|
|
1169
|
-
/**
|
|
1170
|
-
* Force slot-mode rendering on both pages. When omitted, each page falls
|
|
1171
|
-
* through to {@link MejiroPageView}'s automatic choice: slot mode for pages
|
|
1172
|
-
* with images, native `writing-mode: vertical-rl` otherwise.
|
|
1173
|
-
*/
|
|
1174
|
-
slotMode?: boolean;
|
|
1175
|
-
/** Custom renderer for per-page headers. */
|
|
1176
|
-
renderPageHeader?: (side: 'right' | 'left', header: PageHeaderData) => ReactNode;
|
|
1177
|
-
/** Custom indicator placed inside the spread (e.g. {@link MejiroPageIndicator}). */
|
|
1178
|
-
indicator?: ReactNode;
|
|
1179
|
-
/** Called when the previous-page zone is clicked. */
|
|
1180
|
-
onPrev?: () => void;
|
|
1181
|
-
/** Called when the next-page zone is clicked. */
|
|
1182
|
-
onNext?: () => void;
|
|
1183
|
-
/** Pointer-down on an image overlay. */
|
|
1184
|
-
onImagePointerDown?: (id: string, e: PointerEvent) => void;
|
|
1185
|
-
/** Pointer-down on an image resize handle. */
|
|
1186
|
-
onImageResizePointerDown?: (id: string, e: PointerEvent) => void;
|
|
1187
|
-
/** Image overlay close button. */
|
|
1188
|
-
onImageClose?: (id: string) => void;
|
|
1189
|
-
/**
|
|
1190
|
-
* Resolves a spread-local pixel coordinate to an in-chapter anchor.
|
|
1191
|
-
* Typically `(x, y) => layout.anchorAtCoord(spreadIdx, x, y)`. When provided
|
|
1192
|
-
* together with {@link MejiroSpreadProps.onSelectionChange}, the spread
|
|
1193
|
-
* enables pointer-drag selection on the page content area.
|
|
1194
|
-
*/
|
|
1195
|
-
anchorAtCoord?: (x: number, y: number) => InChapterAnchor | null;
|
|
1196
|
-
/**
|
|
1197
|
-
* Zero-based index of the spread being rendered. Rectangles passed through
|
|
1198
|
-
* {@link MejiroSpreadProps.selectionRects} carry spread-local coordinates,
|
|
1199
|
-
* so this is what scopes them to this spread. When omitted, every supplied
|
|
1200
|
-
* rectangle is painted.
|
|
1201
|
-
*/
|
|
1202
|
-
spreadIdx?: number;
|
|
1203
|
-
/**
|
|
1204
|
-
* Selection rectangles to render as a highlight overlay. Compute via
|
|
1205
|
-
* {@link ChapterLayout.selectionRects}. Entries whose `spreadIdx` differs
|
|
1206
|
-
* from {@link MejiroSpreadProps.spreadIdx} are ignored. An entry may carry
|
|
1207
|
-
* a `color` that becomes that rectangle's fill.
|
|
1208
|
-
*/
|
|
1209
|
-
selectionRects?: readonly (AnchorRect & {
|
|
1210
|
-
color?: string;
|
|
1211
|
-
})[];
|
|
1212
|
-
/**
|
|
1213
|
-
* Called when the user drags-selects text on the spread.
|
|
1214
|
-
* Called with `null` on a single-click (caret) where start equals end.
|
|
1215
|
-
*/
|
|
1216
|
-
onSelectionChange?: (range: AnchorRange | null) => void;
|
|
1217
|
-
/**
|
|
1218
|
-
* Render only one page of the spread (centered), chosen by
|
|
1219
|
-
* {@link MejiroSpreadProps.singleSide}. Use this for portrait viewports or
|
|
1220
|
-
* when a reader explicitly opts into single-page mode.
|
|
1221
|
-
*/
|
|
1222
|
-
singlePage?: boolean;
|
|
1223
|
-
/**
|
|
1224
|
-
* Page of the spread shown when {@link MejiroSpreadProps.singlePage} is set
|
|
1225
|
-
* (`useSpread` reports it as `singleSide`). @defaultValue 'right'
|
|
1226
|
-
*/
|
|
1227
|
-
singleSide?: 'right' | 'left';
|
|
1228
|
-
/**
|
|
1229
|
-
* Called when the user makes a quick swipe gesture on the spread.
|
|
1230
|
-
* `direction === 'next'` means the user swiped from right to left (the
|
|
1231
|
-
* natural direction in vertical-rl for advancing).
|
|
1232
|
-
*/
|
|
1233
|
-
onSwipe?: (direction: 'next' | 'prev') => void;
|
|
1234
|
-
/** Called when the user taps the center area without swiping. */
|
|
1235
|
-
onSurfaceTap?: () => void;
|
|
1236
|
-
}
|
|
1237
|
-
/**
|
|
1238
|
-
* Renders a two-page spread (or one page of it in single-page mode) with the
|
|
1239
|
-
* book frame, page chrome, navigation zones, and image overlays. Used inside
|
|
1240
|
-
* `mejiro-reader-surface`.
|
|
1441
|
+
* Renders a selection-highlight overlay inside a page-content container.
|
|
1442
|
+
*
|
|
1443
|
+
* Use as a child of `.mejiro-reader-page-clip` (or any element that shares the
|
|
1444
|
+
* page's content coordinate frame). The layer is pointer-transparent so it
|
|
1445
|
+
* does not interfere with selection drag on the page below.
|
|
1446
|
+
*/
|
|
1447
|
+
declare const MejiroSelectionLayer: react.ForwardRefExoticComponent<MejiroSelectionLayerProps & react.RefAttributes<HTMLDivElement>>;
|
|
1448
|
+
|
|
1449
|
+
/** A single volume in a multi-book library. */
|
|
1450
|
+
interface VolumeInfo<T = unknown> {
|
|
1451
|
+
/** Stable identifier (e.g. ISBN, slug, internal ID). */
|
|
1452
|
+
id: string;
|
|
1453
|
+
/** Human-readable title shown in pickers. */
|
|
1454
|
+
label: string;
|
|
1455
|
+
/** Optional author / byline. */
|
|
1456
|
+
author?: string;
|
|
1457
|
+
/** Optional cover image URL. */
|
|
1458
|
+
cover?: string;
|
|
1459
|
+
/** Free-form metadata attached by the host. */
|
|
1460
|
+
meta?: T;
|
|
1461
|
+
}
|
|
1462
|
+
/** Options for {@link useLibrary}. */
|
|
1463
|
+
interface UseLibraryOptions<T = unknown> {
|
|
1464
|
+
/** The volumes available to the reader. */
|
|
1465
|
+
volumes: readonly VolumeInfo<T>[];
|
|
1466
|
+
/** ID of the volume to start on. Defaults to the first entry. */
|
|
1467
|
+
initialVolumeId?: string;
|
|
1468
|
+
/** Called with the new active volume whenever it changes. */
|
|
1469
|
+
onVolumeChange?: (volume: VolumeInfo<T>) => void;
|
|
1470
|
+
}
|
|
1471
|
+
/** Return value of {@link useLibrary}. */
|
|
1472
|
+
interface UseLibraryReturn<T = unknown> {
|
|
1473
|
+
/** The list of volumes (same reference as the options input). */
|
|
1474
|
+
list: readonly VolumeInfo<T>[];
|
|
1475
|
+
/** Currently active volume, or `null` for an empty library. */
|
|
1476
|
+
volume: VolumeInfo<T> | null;
|
|
1477
|
+
/** Index of the active volume in the list, or `-1` for an empty library. */
|
|
1478
|
+
volumeIndex: number;
|
|
1479
|
+
/** Advance to the next volume in the list (no-op at the end). */
|
|
1480
|
+
next(): void;
|
|
1481
|
+
/** Go back to the previous volume in the list (no-op at the start). */
|
|
1482
|
+
prev(): void;
|
|
1483
|
+
/** Make the volume with the given ID active. No-op when the ID is not in the list. */
|
|
1484
|
+
selectVolume(id: string): void;
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Headless hook for managing a multi-volume reading session. Pair it with
|
|
1488
|
+
* {@link MejiroReader} (driving its `epub` / `epubUrl` prop) or
|
|
1489
|
+
* {@link MejiroShelf} (visual picker).
|
|
1490
|
+
*/
|
|
1491
|
+
declare function useLibrary<T = unknown>(options: UseLibraryOptions<T>): UseLibraryReturn<T>;
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Props for {@link MejiroShelf}; other `section` attributes go to the root
|
|
1495
|
+
* element, except `title`, which here is the heading text.
|
|
1496
|
+
*/
|
|
1497
|
+
interface MejiroShelfProps<T = unknown> extends ComponentPropsWithoutRef<'section'> {
|
|
1498
|
+
/** Volumes to display. */
|
|
1499
|
+
volumes: readonly VolumeInfo<T>[];
|
|
1500
|
+
/** ID of the currently active volume (highlighted in the grid). */
|
|
1501
|
+
currentId?: string;
|
|
1502
|
+
/** Called with the volume the user picks. */
|
|
1503
|
+
onVolumeSelect?: (volume: VolumeInfo<T>) => void;
|
|
1504
|
+
/** Heading shown above the grid. Defaults to the active message catalog's `shelfTitle`. */
|
|
1505
|
+
title?: string;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Visual bookshelf picker. Renders each volume as a card with cover, label,
|
|
1509
|
+
* and author. Pair with {@link useLibrary} to drive selection.
|
|
1241
1510
|
*/
|
|
1242
|
-
declare
|
|
1511
|
+
declare const MejiroShelf: <T = unknown>(props: MejiroShelfProps<T> & RefAttributes<HTMLElement>) => ReactNode;
|
|
1243
1512
|
|
|
1244
|
-
/** Props for {@link MejiroStats}. */
|
|
1245
|
-
interface MejiroStatsProps {
|
|
1513
|
+
/** Props for {@link MejiroStats}; other `span` attributes go to the root element. */
|
|
1514
|
+
interface MejiroStatsProps extends ComponentPropsWithoutRef<'span'> {
|
|
1246
1515
|
/** Chapter currently displayed. */
|
|
1247
1516
|
chapter: EpubChapter | null;
|
|
1248
|
-
/**
|
|
1249
|
-
|
|
1517
|
+
/** Number of pages in the current layout. */
|
|
1518
|
+
pageCount: number;
|
|
1250
1519
|
/** Most recent layout time in ms. */
|
|
1251
1520
|
elapsedMs: number;
|
|
1252
1521
|
/** Optional label for the current font (e.g. "Noto Serif JP 16px"). */
|
|
1253
1522
|
fontLabel?: string;
|
|
1254
1523
|
/** Show estimated reading time in the stats line. @defaultValue false */
|
|
1255
1524
|
showReadingTime?: boolean;
|
|
1256
|
-
/** Characters
|
|
1257
|
-
|
|
1258
|
-
/**
|
|
1259
|
-
|
|
1525
|
+
/** Characters per minute used for the reading-time estimate. @defaultValue 600 */
|
|
1526
|
+
charsPerMinute?: number;
|
|
1527
|
+
/**
|
|
1528
|
+
* Locale whose catalog spells the reading-time units. Defaults to the
|
|
1529
|
+
* catalog of the nearest `MejiroI18nProvider`.
|
|
1530
|
+
*/
|
|
1531
|
+
locale?: MejiroLocale;
|
|
1260
1532
|
}
|
|
1261
1533
|
/** Compact reading stats line. */
|
|
1262
|
-
declare
|
|
1534
|
+
declare const MejiroStats: react.ForwardRefExoticComponent<MejiroStatsProps & react.RefAttributes<HTMLSpanElement>>;
|
|
1263
1535
|
|
|
1264
|
-
/**
|
|
1265
|
-
|
|
1536
|
+
/**
|
|
1537
|
+
* Props for {@link MejiroToc}; other `nav` attributes go to the root element,
|
|
1538
|
+
* except `title`, which here is the heading text.
|
|
1539
|
+
*/
|
|
1540
|
+
interface MejiroTocProps extends ComponentPropsWithoutRef<'nav'> {
|
|
1266
1541
|
/** EPUB whose chapter list is rendered. */
|
|
1267
1542
|
epub: EpubBook;
|
|
1268
1543
|
/** Current reading anchor; the matching chapter is highlighted. */
|
|
1269
1544
|
currentAnchor?: ReadingAnchor | null;
|
|
1270
1545
|
/** Show a search input that filters chapter titles. @defaultValue false */
|
|
1271
|
-
|
|
1546
|
+
showSearch?: boolean;
|
|
1272
1547
|
/** Heading displayed above the list. Defaults to the active message catalog's `tocTitle`. */
|
|
1273
1548
|
title?: string;
|
|
1274
1549
|
/** Placeholder shown in the search input. Defaults to the active message catalog's `tocSearchPlaceholder`. */
|
|
1275
1550
|
searchPlaceholder?: string;
|
|
1276
|
-
/** Called
|
|
1277
|
-
|
|
1278
|
-
}
|
|
1279
|
-
/**
|
|
1280
|
-
* Searchable, current-anchor-aware table of contents. Long-form replacement
|
|
1281
|
-
* for {@link MejiroChapterNav}. Supersedes the older `MejiroChapterNav`
|
|
1282
|
-
* for new code — the panel variant remains for backwards compatibility.
|
|
1283
|
-
*/
|
|
1284
|
-
declare function MejiroToc({ epub, currentAnchor, searchable, title, searchPlaceholder, onSelect, }: MejiroTocProps): ReactNode;
|
|
1285
|
-
|
|
1286
|
-
/** Minimal storage interface required by {@link useAnnotations}. */
|
|
1287
|
-
type AnnotationsStorage = MejiroStorage;
|
|
1288
|
-
/** Options for {@link useAnnotations}. */
|
|
1289
|
-
interface UseAnnotationsOptions {
|
|
1290
|
-
/** Storage key — usually scoped per-book (e.g. `mejiro:annotations:${bookId}`). */
|
|
1291
|
-
key: string;
|
|
1292
|
-
/**
|
|
1293
|
-
* Storage backend. Defaults to `window.localStorage` when available.
|
|
1294
|
-
* SSR consumers can omit this and the hook will fall back to in-memory.
|
|
1295
|
-
* The latest reference is always used, so an object literal recreated on
|
|
1296
|
-
* every render is safe — only `key` triggers a re-hydration.
|
|
1297
|
-
*/
|
|
1298
|
-
storage?: AnnotationsStorage;
|
|
1299
|
-
/**
|
|
1300
|
-
* Debounce delay (ms): the latest value is written this long after the last change. A pending write is flushed on page hide, key change and unmount. @defaultValue 250
|
|
1301
|
-
*/
|
|
1302
|
-
throttleMs?: number;
|
|
1303
|
-
/**
|
|
1304
|
-
* Called immediately after each mutation (`add` / `remove` / `update` /
|
|
1305
|
-
* `clear`) with the new annotation list. Use to mirror state to a server
|
|
1306
|
-
* — `storage` only covers the local persistence side. Not invoked on
|
|
1307
|
-
* initial hydration or when the `key` changes.
|
|
1308
|
-
*/
|
|
1309
|
-
onChange?: (next: readonly Annotation[]) => void;
|
|
1310
|
-
}
|
|
1311
|
-
/** Return value of {@link useAnnotations}. */
|
|
1312
|
-
interface UseAnnotationsReturn {
|
|
1313
|
-
/** Currently saved annotations, sorted by chapter / paragraph / charIndex. */
|
|
1314
|
-
annotations: readonly Annotation[];
|
|
1315
|
-
/** Add a new annotation. `id` and `createdAt` are auto-filled when omitted. */
|
|
1316
|
-
add(input: Omit<Annotation, 'id' | 'createdAt'> & Partial<Pick<Annotation, 'id' | 'createdAt'>>): Annotation;
|
|
1317
|
-
/** Remove an annotation by id. */
|
|
1318
|
-
remove(id: string): void;
|
|
1319
|
-
/** Patch an annotation by id. Pass `undefined` on a field to leave it untouched. */
|
|
1320
|
-
update(id: string, patch: Partial<Omit<Annotation, 'id'>>): void;
|
|
1321
|
-
/** Remove all annotations. */
|
|
1322
|
-
clear(): void;
|
|
1551
|
+
/** Called with the zero-based index of the chapter the user picks. */
|
|
1552
|
+
onChapterSelect?: (chapterIndex: number) => void;
|
|
1323
1553
|
}
|
|
1324
1554
|
/**
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
* {@link MejiroReader} to render the corresponding highlight rectangles.
|
|
1328
|
-
*
|
|
1329
|
-
* ```tsx
|
|
1330
|
-
* const { annotations, add } = useAnnotations({ key: `mejiro:ann:${bookId}` });
|
|
1331
|
-
* const handle = useRef<MejiroReaderHandle>(null);
|
|
1332
|
-
*
|
|
1333
|
-
* // Save a highlight at the current visible range:
|
|
1334
|
-
* const range = handle.current?.getVisibleRange();
|
|
1335
|
-
* if (range) add({ chapter: 0, start: range.start, end: range.end, color: 'yellow' });
|
|
1336
|
-
*
|
|
1337
|
-
* <MejiroReader epub={book} annotations={annotations} ref={handle} />
|
|
1338
|
-
* ```
|
|
1555
|
+
* Searchable table of contents that highlights the chapter of the current
|
|
1556
|
+
* reading anchor. For a compact chapter picker, use {@link MejiroChapterNav}.
|
|
1339
1557
|
*/
|
|
1340
|
-
declare
|
|
1558
|
+
declare const MejiroToc: react.ForwardRefExoticComponent<MejiroTocProps & react.RefAttributes<HTMLElement>>;
|
|
1341
1559
|
|
|
1342
1560
|
/** Options for {@link useChapterLayout}. */
|
|
1343
1561
|
interface UseChapterLayoutOptions {
|
|
1562
|
+
/** The parsed EPUB whose chapter is laid out; `null` lays nothing out. */
|
|
1563
|
+
epub: EpubBook | null;
|
|
1564
|
+
/** Zero-based index of the chapter to lay out. */
|
|
1565
|
+
chapterIndex: number;
|
|
1566
|
+
/** The reading surface the pages are sized against. */
|
|
1567
|
+
surface: RefObject<HTMLElement | null>;
|
|
1344
1568
|
/** Observe the surface element for size changes and re-flow. @defaultValue true */
|
|
1345
1569
|
enableResize?: boolean;
|
|
1346
1570
|
/** Debounce window (ms) applied to size-triggered re-flows. @defaultValue 120 */
|
|
1347
|
-
|
|
1571
|
+
resizeDebounceMs?: number;
|
|
1348
1572
|
/**
|
|
1349
1573
|
* Resolver for page-geometry overrides forwarded to
|
|
1350
|
-
* {@link MejiroBook.
|
|
1574
|
+
* {@link MejiroBook.fitPageSize} — e.g. to shrink the reserved
|
|
1351
1575
|
* `gutterOffset` / `headerOffset` so the pages fill their frame. Called on
|
|
1352
1576
|
* every (re)layout so it may return a value that changes over time.
|
|
1353
1577
|
*/
|
|
1354
|
-
pageGeometry?: () =>
|
|
1578
|
+
pageGeometry?: () => FitPageSizeOptions | undefined;
|
|
1355
1579
|
/**
|
|
1356
1580
|
* Capture the reading position from the outgoing layout, just before a
|
|
1357
1581
|
* **reflow** (non-blank) re-layout replaces it. The anchor is held in
|
|
@@ -1374,8 +1598,11 @@ interface UseChapterLayoutOptions {
|
|
|
1374
1598
|
*/
|
|
1375
1599
|
onError?: (error: Error) => void;
|
|
1376
1600
|
}
|
|
1377
|
-
/**
|
|
1378
|
-
|
|
1601
|
+
/**
|
|
1602
|
+
* Options for the `recompute` of {@link useChapterLayout} and
|
|
1603
|
+
* {@link useManuscriptLayout}.
|
|
1604
|
+
*/
|
|
1605
|
+
interface ChapterLayoutRecomputeOptions {
|
|
1379
1606
|
/**
|
|
1380
1607
|
* Blank the current layout while the new one is computed. Use for content
|
|
1381
1608
|
* changes (chapter / book swaps); skip for size or option changes so the
|
|
@@ -1384,20 +1611,11 @@ interface RecomputeOptions {
|
|
|
1384
1611
|
*/
|
|
1385
1612
|
blank?: boolean;
|
|
1386
1613
|
}
|
|
1387
|
-
/** Page dimensions returned by {@link MejiroBook.computePageSize}. */
|
|
1388
|
-
interface PageDimensions {
|
|
1389
|
-
/** Width of one page, in CSS pixels. */
|
|
1390
|
-
pageWidth: number;
|
|
1391
|
-
/** Height of one page, in CSS pixels. */
|
|
1392
|
-
pageHeight: number;
|
|
1393
|
-
/** Height of the text area inside a page, in CSS pixels. */
|
|
1394
|
-
contentHeight: number;
|
|
1395
|
-
}
|
|
1396
1614
|
/** Return value of {@link useChapterLayout}. */
|
|
1397
1615
|
interface UseChapterLayoutReturn {
|
|
1398
1616
|
/** Current layout, or `null` before the first computation. */
|
|
1399
1617
|
layout: ChapterLayout | null;
|
|
1400
|
-
/** Page width in pixels. */
|
|
1618
|
+
/** Page width in pixels, as {@link MejiroBook.fitPageSize} measured it. */
|
|
1401
1619
|
pageWidth: number;
|
|
1402
1620
|
/** Page height in pixels. */
|
|
1403
1621
|
pageHeight: number;
|
|
@@ -1405,11 +1623,16 @@ interface UseChapterLayoutReturn {
|
|
|
1405
1623
|
contentHeight: number;
|
|
1406
1624
|
/** Most recent layout time (ms). */
|
|
1407
1625
|
elapsedMs: number;
|
|
1626
|
+
/**
|
|
1627
|
+
* Failure of the most recent layout of the current source, whichever path
|
|
1628
|
+
* started it; `null` once a layout succeeds or the source changes.
|
|
1629
|
+
*/
|
|
1630
|
+
error: Error | null;
|
|
1408
1631
|
/**
|
|
1409
1632
|
* Force a fresh layout computation. A failure goes to `onError` when one is
|
|
1410
1633
|
* supplied; otherwise the returned promise rejects.
|
|
1411
1634
|
*/
|
|
1412
|
-
recompute: (opts?:
|
|
1635
|
+
recompute: (opts?: ChapterLayoutRecomputeOptions) => Promise<void>;
|
|
1413
1636
|
/**
|
|
1414
1637
|
* Anchor captured by `capturePosition` before the most recent reflow,
|
|
1415
1638
|
* awaiting restoration into the new layout. `restorePosition`, when given,
|
|
@@ -1429,9 +1652,11 @@ interface UseChapterLayoutReturn {
|
|
|
1429
1652
|
*
|
|
1430
1653
|
* Re-layouts whenever `book`, `epub`, or `chapterIndex` change, against the
|
|
1431
1654
|
* dimensions of `surface`. The `surface` element is observed with a
|
|
1432
|
-
* {@link ResizeObserver}: the first observation
|
|
1433
|
-
* mounted before its container had a final box is
|
|
1434
|
-
* first paint), and later size changes trigger a
|
|
1655
|
+
* {@link ResizeObserver}: the first observation of a positive box runs
|
|
1656
|
+
* immediately (so a reader mounted before its container had a final box is
|
|
1657
|
+
* still sized correctly on first paint), and later size changes trigger a
|
|
1658
|
+
* debounced **full re-layout**. While the surface measures zero wide or high,
|
|
1659
|
+
* nothing is measured or laid out.
|
|
1435
1660
|
*
|
|
1436
1661
|
* Size and option changes lay the chapter out again rather than calling
|
|
1437
1662
|
* `ChapterLayout.resize()`, so page geometry is re-derived from the surface and
|
|
@@ -1445,23 +1670,36 @@ interface UseChapterLayoutReturn {
|
|
|
1445
1670
|
* composable.
|
|
1446
1671
|
*
|
|
1447
1672
|
* @param book - The book instance to lay out with.
|
|
1448
|
-
* @param
|
|
1449
|
-
* @param chapterIndex - Zero-based chapter index to lay out.
|
|
1450
|
-
* @param surface - DOM ref for the reading surface used for page sizing.
|
|
1451
|
-
* @param options - Behavior overrides.
|
|
1673
|
+
* @param options - The EPUB, chapter and surface to lay out, plus behavior overrides.
|
|
1452
1674
|
*/
|
|
1453
|
-
declare function useChapterLayout(book: MejiroBook,
|
|
1675
|
+
declare function useChapterLayout(book: MejiroBook, options: UseChapterLayoutOptions): UseChapterLayoutReturn;
|
|
1454
1676
|
|
|
1455
1677
|
/** Options for {@link useEditableEpub}. */
|
|
1456
1678
|
interface UseEditableEpubOptions {
|
|
1457
|
-
/**
|
|
1458
|
-
|
|
1679
|
+
/**
|
|
1680
|
+
* URL to load. Fetched on mount and again whenever it changes; clearing it
|
|
1681
|
+
* abandons a load still in flight and keeps the current editor.
|
|
1682
|
+
*/
|
|
1683
|
+
url?: string;
|
|
1459
1684
|
/** Called after a successful load. */
|
|
1460
1685
|
onLoad?: (editor: EditableEpub) => void;
|
|
1461
|
-
/**
|
|
1686
|
+
/**
|
|
1687
|
+
* Called when a load or an export fails. A `MejiroError` is passed as
|
|
1688
|
+
* thrown; a failed export also rejects the promise `exportEpub` returned.
|
|
1689
|
+
*/
|
|
1462
1690
|
onError?: (error: Error) => void;
|
|
1463
|
-
/** Called after export completes. */
|
|
1464
|
-
onExport?: (
|
|
1691
|
+
/** Called with the EPUB bytes after an export completes. */
|
|
1692
|
+
onExport?: (bytes: Uint8Array<ArrayBuffer>) => void;
|
|
1693
|
+
/**
|
|
1694
|
+
* Extra options merged into the `fetch` call when loading by URL. Useful
|
|
1695
|
+
* for sending bearer tokens or cookies (`credentials: 'include'`).
|
|
1696
|
+
*/
|
|
1697
|
+
fetchOptions?: RequestInit;
|
|
1698
|
+
/**
|
|
1699
|
+
* Custom EPUB fetcher used in place of the global `fetch`. Resolves to the
|
|
1700
|
+
* raw bytes. Overrides {@link UseEditableEpubOptions.fetchOptions} when set.
|
|
1701
|
+
*/
|
|
1702
|
+
fetchEpub?: (url: string, options: FetchEpubOptions) => Promise<BinaryInput>;
|
|
1465
1703
|
/**
|
|
1466
1704
|
* Archive resource limits applied while opening an EPUB. Raise them for
|
|
1467
1705
|
* trusted, image-heavy books; tighten them for a public drop zone. Omitted
|
|
@@ -1476,131 +1714,101 @@ interface UseEditableEpubOptions {
|
|
|
1476
1714
|
}
|
|
1477
1715
|
/** Return value of {@link useEditableEpub}. */
|
|
1478
1716
|
interface UseEditableEpubReturn {
|
|
1479
|
-
/**
|
|
1717
|
+
/**
|
|
1718
|
+
* Loaded editing session, or `null` before any load. Edits made on it
|
|
1719
|
+
* directly are picked up like the hook's own: the hook subscribes to it and
|
|
1720
|
+
* advances `revision` on every change.
|
|
1721
|
+
*/
|
|
1480
1722
|
editor: EditableEpub | null;
|
|
1481
1723
|
/** The editor's live document, or `null` before any load. */
|
|
1482
|
-
|
|
1483
|
-
/**
|
|
1484
|
-
|
|
1724
|
+
epub: EditableEpubBook | null;
|
|
1725
|
+
/**
|
|
1726
|
+
* The document projected onto the reader's {@link EpubBook} shape, rebuilt
|
|
1727
|
+
* on every change, for feeding a preview reader.
|
|
1728
|
+
*/
|
|
1729
|
+
previewEpub: EpubBook | null;
|
|
1485
1730
|
/** Whether a load is in progress. */
|
|
1486
1731
|
loading: boolean;
|
|
1487
1732
|
/** Whether an export is in progress. */
|
|
1488
1733
|
exporting: boolean;
|
|
1489
|
-
/** Last load error, if any. */
|
|
1734
|
+
/** Last load or export error, if any. */
|
|
1490
1735
|
error: Error | null;
|
|
1491
|
-
/** Counter
|
|
1736
|
+
/** Counter advanced on every load and every change to the document. */
|
|
1492
1737
|
revision: number;
|
|
1493
1738
|
/** Undo / redo availability, or `null` before any load. */
|
|
1494
|
-
history:
|
|
1495
|
-
|
|
1496
|
-
canRedo: boolean;
|
|
1497
|
-
depth: number;
|
|
1498
|
-
redoDepth: number;
|
|
1499
|
-
} | null;
|
|
1500
|
-
/** Paragraph targeted by the editing commands. */
|
|
1739
|
+
history: EditHistoryState | null;
|
|
1740
|
+
/** Block targeted by the editing commands. */
|
|
1501
1741
|
selection: EditableEpubSelection;
|
|
1502
|
-
/** The paragraph at `selection`, or `null` when
|
|
1503
|
-
selectedParagraph:
|
|
1504
|
-
/** Moves the selection, clamped to the loaded
|
|
1742
|
+
/** The paragraph block at `selection`, or `null` when no paragraph is selected. */
|
|
1743
|
+
selectedParagraph: EditableParagraphBlock | null;
|
|
1744
|
+
/** Moves the selection, clamped to the loaded document. */
|
|
1505
1745
|
setSelection: (selection: EditableEpubSelection) => void;
|
|
1506
|
-
/**
|
|
1507
|
-
|
|
1746
|
+
/**
|
|
1747
|
+
* Loads an EPUB from in-memory bytes. A `Uint8Array` is read through its own
|
|
1748
|
+
* view and is neither retained nor modified.
|
|
1749
|
+
*/
|
|
1750
|
+
loadBuffer: (bytes: BinaryInput) => Promise<EditableEpub | null>;
|
|
1508
1751
|
/** Loads an EPUB from a {@link File}. */
|
|
1509
1752
|
loadFile: (file: File) => Promise<EditableEpub | null>;
|
|
1510
|
-
/** Fetches and loads an EPUB; a non-2xx response is reported as
|
|
1753
|
+
/** Fetches and loads an EPUB; a non-2xx response is reported as `fetch-failed`. */
|
|
1511
1754
|
loadUrl: (url: string) => Promise<EditableEpub | null>;
|
|
1512
|
-
/**
|
|
1513
|
-
|
|
1514
|
-
|
|
1755
|
+
/**
|
|
1756
|
+
* Applies `patch` to the selected paragraph, as
|
|
1757
|
+
* {@link EditableEpub.updateParagraph} does. Does nothing when no block is
|
|
1758
|
+
* selected.
|
|
1759
|
+
*/
|
|
1760
|
+
updateParagraph: (patch: ParagraphPatch) => void;
|
|
1761
|
+
/** Replaces the selected paragraph's inline annotations. Does nothing when no block is selected. */
|
|
1515
1762
|
setInlineAnnotations: (inlineAnnotations: readonly InlineAnnotation[]) => void;
|
|
1516
|
-
/**
|
|
1517
|
-
|
|
1763
|
+
/**
|
|
1764
|
+
* Inserts an image into the selected chapter, as {@link EditableEpub.addImage}
|
|
1765
|
+
* does, and returns the stored block; `null` before any load.
|
|
1766
|
+
*/
|
|
1767
|
+
addImage: (image: AddImageInput) => EditableImageBlock | null;
|
|
1518
1768
|
/** Reverts the last edit. Returns `false` when there is nothing to undo. */
|
|
1519
1769
|
undo: () => boolean;
|
|
1520
1770
|
/** Re-applies the last undone edit. Returns `false` when there is nothing to redo. */
|
|
1521
1771
|
redo: () => boolean;
|
|
1522
|
-
/** Packages the edited document as an EPUB buffer. */
|
|
1523
|
-
exportEpub: (options?: EpubExportOptions) => Promise<ArrayBuffer | null>;
|
|
1524
|
-
}
|
|
1525
|
-
/** Headless editable-EPUB state for custom proofreading/editor UIs. */
|
|
1526
|
-
declare function useEditableEpub(options?: UseEditableEpubOptions): UseEditableEpubReturn;
|
|
1527
|
-
|
|
1528
|
-
/** Options for {@link useEpub}. */
|
|
1529
|
-
interface UseEpubOptions {
|
|
1530
|
-
/** URL fetched on mount. */
|
|
1531
|
-
defaultUrl?: string;
|
|
1532
|
-
/** Called after a successful load. */
|
|
1533
|
-
onLoad?: (book: EpubBook) => void;
|
|
1534
|
-
/** Called when a load fails, including a non-2xx URL response. */
|
|
1535
|
-
onError?: (error: Error) => void;
|
|
1536
|
-
/**
|
|
1537
|
-
* Extra options merged into the `fetch` call when loading by URL. Useful
|
|
1538
|
-
* for sending bearer tokens or cookies (`credentials: 'include'`).
|
|
1539
|
-
*/
|
|
1540
|
-
fetchOptions?: RequestInit;
|
|
1541
1772
|
/**
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
* for hosts that already own an auth-aware HTTP client.
|
|
1545
|
-
*/
|
|
1546
|
-
fetchEpub?: (url: string) => Promise<ArrayBuffer>;
|
|
1547
|
-
/**
|
|
1548
|
-
* Archive resource limits applied while opening an EPUB. Raise them for
|
|
1549
|
-
* trusted, image-heavy books; tighten them for a public drop zone. Omitted
|
|
1550
|
-
* fields keep their `DEFAULT_EPUB_PARSE_LIMITS` value.
|
|
1773
|
+
* Packages the edited document as EPUB bytes; `null` before any load. A
|
|
1774
|
+
* failure is stored in `error`, passed to `onError` and rejects.
|
|
1551
1775
|
*/
|
|
1552
|
-
|
|
1553
|
-
}
|
|
1554
|
-
/** Return value of {@link useEpub}. */
|
|
1555
|
-
interface UseEpubReturn {
|
|
1556
|
-
/** Current parsed EPUB, or `null` before any load. */
|
|
1557
|
-
epub: EpubBook | null;
|
|
1558
|
-
/** Whether a load is in progress. */
|
|
1559
|
-
loading: boolean;
|
|
1560
|
-
/** Last load error, if any. */
|
|
1561
|
-
error: Error | null;
|
|
1562
|
-
/** Parse from an in-memory buffer. */
|
|
1563
|
-
loadBuffer: (buffer: ArrayBuffer) => Promise<EpubBook | null>;
|
|
1564
|
-
/** Parse from a {@link File}. */
|
|
1565
|
-
loadFile: (file: File) => Promise<EpubBook | null>;
|
|
1566
|
-
/** Fetch a URL and parse the response. */
|
|
1567
|
-
loadUrl: (url: string) => Promise<EpubBook | null>;
|
|
1568
|
-
/** Replace the current EPUB without going through the parser. */
|
|
1569
|
-
setEpub: (book: EpubBook | null) => void;
|
|
1776
|
+
exportEpub: (options?: EditableEpubExportOptions) => Promise<Uint8Array<ArrayBuffer> | null>;
|
|
1570
1777
|
}
|
|
1571
1778
|
/**
|
|
1572
|
-
*
|
|
1573
|
-
*
|
|
1779
|
+
* Headless editable-EPUB state for custom proofreading/editor UIs.
|
|
1780
|
+
*
|
|
1781
|
+
* One load runs at a time: starting another, changing `url` or unmounting
|
|
1782
|
+
* aborts the one in flight — its fetch and parse included — and its result is
|
|
1783
|
+
* dropped.
|
|
1574
1784
|
*/
|
|
1575
|
-
declare function
|
|
1785
|
+
declare function useEditableEpub(options?: UseEditableEpubOptions): UseEditableEpubReturn;
|
|
1576
1786
|
|
|
1577
|
-
/** One chapter of the manuscript draft the hook keeps in React state. */
|
|
1578
|
-
interface EpubProjectChapterDraft {
|
|
1579
|
-
/** Stable chapter identifier. */
|
|
1580
|
-
id: string;
|
|
1581
|
-
/** Chapter title. */
|
|
1582
|
-
title: string;
|
|
1583
|
-
/** Chapter body in the manuscript notation. */
|
|
1584
|
-
body: string;
|
|
1585
|
-
}
|
|
1586
1787
|
/** Options for {@link useEpubProject}. */
|
|
1587
1788
|
interface UseEpubProjectOptions {
|
|
1588
|
-
/**
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1789
|
+
/**
|
|
1790
|
+
* Package metadata on mount. The title defaults to `''` and the language to
|
|
1791
|
+
* `'ja'`; a missing or blank identifier is generated.
|
|
1792
|
+
*/
|
|
1793
|
+
initialMetadata?: Partial<EpubProjectMetadata>;
|
|
1794
|
+
/**
|
|
1795
|
+
* Chapters on mount. When absent or empty, one chapter is generated from
|
|
1796
|
+
* {@link UseEpubProjectOptions.defaultChapterTitle} /
|
|
1797
|
+
* {@link UseEpubProjectOptions.defaultChapterBody}.
|
|
1798
|
+
*/
|
|
1799
|
+
initialChapters?: readonly ManuscriptChapter$1[];
|
|
1592
1800
|
/** Preview rebuild debounce in milliseconds. @defaultValue 250 */
|
|
1593
1801
|
debounceMs?: number;
|
|
1594
1802
|
/**
|
|
1595
|
-
*
|
|
1596
|
-
* export, or `{
|
|
1803
|
+
* Cover on mount. Pass `{ url, mediaType }` to keep the bytes remote until
|
|
1804
|
+
* export, or `{ data, mediaType }` to embed them straight away.
|
|
1597
1805
|
*/
|
|
1598
|
-
|
|
1806
|
+
initialCover?: CoverInput;
|
|
1599
1807
|
/**
|
|
1600
|
-
*
|
|
1601
|
-
* `data` / `url` choice as {@link UseEpubProjectOptions.
|
|
1808
|
+
* Non-cover assets on mount (illustrations, extra stylesheets). Same
|
|
1809
|
+
* `data` / `url` choice as {@link UseEpubProjectOptions.initialCover}.
|
|
1602
1810
|
*/
|
|
1603
|
-
|
|
1811
|
+
initialAssets?: readonly EpubProjectAsset[];
|
|
1604
1812
|
/**
|
|
1605
1813
|
* Resolves URL-only project assets into bytes when the preview or export
|
|
1606
1814
|
* pipeline materializes them. Forwarded to `project.export()`. Register the
|
|
@@ -1609,63 +1817,76 @@ interface UseEpubProjectOptions {
|
|
|
1609
1817
|
* provide auth headers here.
|
|
1610
1818
|
*/
|
|
1611
1819
|
assetResolver?: AssetResolver;
|
|
1612
|
-
/** Called with each successfully rebuilt preview
|
|
1613
|
-
onPreview?: (
|
|
1820
|
+
/** Called with each successfully rebuilt preview EPUB. */
|
|
1821
|
+
onPreview?: (epub: EpubBook) => void;
|
|
1614
1822
|
/** Called with the EPUB bytes produced by {@link UseEpubProjectReturn.exportEpub}. */
|
|
1615
|
-
onExport?: (
|
|
1616
|
-
/**
|
|
1823
|
+
onExport?: (bytes: Uint8Array<ArrayBuffer>) => void;
|
|
1824
|
+
/**
|
|
1825
|
+
* Called when an export fails; the promise `exportEpub` returned rejects
|
|
1826
|
+
* too. A `MejiroError` is passed as thrown. Preview failures go to
|
|
1827
|
+
* {@link UseEpubProjectReturn.previewError} instead.
|
|
1828
|
+
*/
|
|
1829
|
+
onError?: (error: Error) => void;
|
|
1830
|
+
/** Creates the title of a generated chapter. @defaultValue `() => ''` */
|
|
1617
1831
|
defaultChapterTitle?: (index: number) => string;
|
|
1618
|
-
/** Creates the
|
|
1832
|
+
/** Creates the body of a generated chapter. @defaultValue `() => ''` */
|
|
1619
1833
|
defaultChapterBody?: (index: number) => string;
|
|
1620
1834
|
}
|
|
1621
1835
|
/** State and actions returned by {@link useEpubProject}. */
|
|
1622
1836
|
interface UseEpubProjectReturn {
|
|
1623
1837
|
/** Current book metadata. */
|
|
1624
1838
|
metadata: EpubProjectMetadata;
|
|
1625
|
-
/** Current
|
|
1626
|
-
chapters:
|
|
1839
|
+
/** Current chapters, in reading order. */
|
|
1840
|
+
chapters: readonly ManuscriptChapter$1[];
|
|
1627
1841
|
/** Index of the chapter being edited. */
|
|
1628
|
-
|
|
1629
|
-
/** The chapter at `
|
|
1630
|
-
currentChapter:
|
|
1631
|
-
/** Current cover
|
|
1632
|
-
cover:
|
|
1842
|
+
selectedChapterIndex: number;
|
|
1843
|
+
/** The chapter at `selectedChapterIndex`, or `null` when there is none. */
|
|
1844
|
+
currentChapter: ManuscriptChapter$1 | null;
|
|
1845
|
+
/** Current cover, or `null` when the project has no cover. */
|
|
1846
|
+
cover: CoverInput | null;
|
|
1633
1847
|
/** Current non-cover assets, in registration order. */
|
|
1634
|
-
assets: EpubProjectAsset[];
|
|
1848
|
+
assets: readonly EpubProjectAsset[];
|
|
1635
1849
|
/** Parsed EPUB built from the current project, refreshed after each debounced change. */
|
|
1636
|
-
|
|
1850
|
+
previewEpub: EpubBook | null;
|
|
1637
1851
|
/** Last preview build failure, if any. */
|
|
1638
1852
|
previewError: Error | null;
|
|
1639
1853
|
/** Whether a preview build is pending or running. */
|
|
1640
1854
|
previewing: boolean;
|
|
1855
|
+
/** Whether an export is in progress. */
|
|
1856
|
+
exporting: boolean;
|
|
1857
|
+
/** Last export failure, if any; cleared when an export starts. */
|
|
1858
|
+
error: Error | null;
|
|
1641
1859
|
/**
|
|
1642
1860
|
* Merges `patch` into the metadata. A missing or blank `identifier` keeps the
|
|
1643
1861
|
* current one.
|
|
1644
1862
|
*/
|
|
1645
|
-
|
|
1863
|
+
updateMetadata: (patch: Partial<EpubProjectMetadata>) => void;
|
|
1646
1864
|
/** Replaces every chapter; an empty list becomes one generated chapter. */
|
|
1647
|
-
setChapters: (chapters:
|
|
1865
|
+
setChapters: (chapters: readonly ManuscriptChapter$1[]) => void;
|
|
1648
1866
|
/** Selects a chapter, clamped to the chapter range. */
|
|
1649
|
-
|
|
1867
|
+
setSelectedChapterIndex: (index: number) => void;
|
|
1650
1868
|
/**
|
|
1651
|
-
* Replaces the cover
|
|
1869
|
+
* Replaces the cover, or drops it when passed `null`. The new cover is
|
|
1652
1870
|
* reflected by both the debounced preview and {@link UseEpubProjectReturn.exportEpub}.
|
|
1653
1871
|
*/
|
|
1654
|
-
setCover: (
|
|
1872
|
+
setCover: (cover: CoverInput | null) => void;
|
|
1655
1873
|
/**
|
|
1656
1874
|
* Replaces the non-cover asset list. Assets are registered on every rebuilt
|
|
1657
1875
|
* project, so URL-only entries reach `assetResolver` at export time.
|
|
1658
1876
|
*/
|
|
1659
|
-
setAssets: (assets: EpubProjectAsset[]) => void;
|
|
1877
|
+
setAssets: (assets: readonly EpubProjectAsset[]) => void;
|
|
1660
1878
|
/** Merges `patch` into the chapter at `index`. */
|
|
1661
|
-
|
|
1662
|
-
/**
|
|
1663
|
-
|
|
1879
|
+
updateChapter: (index: number, patch: Partial<ManuscriptChapter$1>) => void;
|
|
1880
|
+
/**
|
|
1881
|
+
* Appends a chapter and selects it. Omitted fields are generated: a unique
|
|
1882
|
+
* id, and the title and body of `defaultChapterTitle` / `defaultChapterBody`.
|
|
1883
|
+
*/
|
|
1884
|
+
addChapter: (chapter?: Partial<ManuscriptChapter$1>) => void;
|
|
1664
1885
|
/**
|
|
1665
|
-
* Removes the chapter at `index
|
|
1666
|
-
* removed.
|
|
1886
|
+
* Removes the chapter at `index`; the last remaining chapter is never
|
|
1887
|
+
* removed. Pass `selectedChapterIndex` to remove the selected one.
|
|
1667
1888
|
*/
|
|
1668
|
-
removeChapter: (index
|
|
1889
|
+
removeChapter: (index: number) => void;
|
|
1669
1890
|
/**
|
|
1670
1891
|
* Moves a chapter from `from` to `to`. An out-of-range `from` selects no
|
|
1671
1892
|
* chapter and leaves the list untouched; `to` is clamped to the list bounds —
|
|
@@ -1674,49 +1895,64 @@ interface UseEpubProjectReturn {
|
|
|
1674
1895
|
reorderChapters: (from: number, to: number) => void;
|
|
1675
1896
|
/** Builds an `EpubProject` from the current state. */
|
|
1676
1897
|
buildProject: () => EpubProject;
|
|
1677
|
-
/**
|
|
1678
|
-
|
|
1898
|
+
/**
|
|
1899
|
+
* Packages the current project as EPUB bytes. A failure is stored in
|
|
1900
|
+
* `error`, passed to `onError` and rejects.
|
|
1901
|
+
*/
|
|
1902
|
+
exportEpub: () => Promise<Uint8Array<ArrayBuffer>>;
|
|
1679
1903
|
}
|
|
1680
1904
|
/** Headless manuscript-to-EPUB project state for custom authoring UIs. */
|
|
1681
1905
|
declare function useEpubProject(options?: UseEpubProjectOptions): UseEpubProjectReturn;
|
|
1682
1906
|
|
|
1683
1907
|
/** Options for {@link useManuscriptDraft}. */
|
|
1684
|
-
interface UseManuscriptDraftOptions<TAutosave =
|
|
1685
|
-
/**
|
|
1686
|
-
|
|
1908
|
+
interface UseManuscriptDraftOptions<TAutosave = ManuscriptChapter$1[]> {
|
|
1909
|
+
/**
|
|
1910
|
+
* Initial chapters, read on mount. Defaults to a single chapter with an
|
|
1911
|
+
* empty title and body.
|
|
1912
|
+
*/
|
|
1913
|
+
initialChapters?: readonly ManuscriptChapter$1[];
|
|
1687
1914
|
/**
|
|
1688
|
-
* Called when the draft changes (debounced).
|
|
1689
|
-
*
|
|
1915
|
+
* Called when the draft changes (debounced). This is the persistence
|
|
1916
|
+
* channel of the hook, and it may be async: return a promise to have the
|
|
1917
|
+
* next save wait for it and to have a rejection land in `autosaveError`.
|
|
1918
|
+
* Use it to write to localStorage or IndexedDB, or to upload to a server.
|
|
1690
1919
|
*/
|
|
1691
1920
|
onAutosave?: (draft: TAutosave) => void | Promise<void>;
|
|
1692
1921
|
/** Maps chapters to the autosave payload. Defaults to the chapter array. */
|
|
1693
|
-
autosavePayload?: (chapters:
|
|
1694
|
-
/**
|
|
1695
|
-
|
|
1922
|
+
autosavePayload?: (chapters: readonly ManuscriptChapter$1[]) => TAutosave;
|
|
1923
|
+
/**
|
|
1924
|
+
* Values outside the chapters that the autosave payload depends on (a
|
|
1925
|
+
* title, an author). A change to any of them, compared with `Object.is`,
|
|
1926
|
+
* schedules an autosave like a chapter edit does.
|
|
1927
|
+
*/
|
|
1928
|
+
autosaveDeps?: readonly unknown[];
|
|
1696
1929
|
/** Debounce delay in milliseconds. @defaultValue 800 */
|
|
1697
|
-
|
|
1698
|
-
/** Creates the
|
|
1930
|
+
autosaveDebounceMs?: number;
|
|
1931
|
+
/** Creates the title of a generated chapter. @defaultValue `() => ''` */
|
|
1699
1932
|
defaultChapterTitle?: (index: number) => string;
|
|
1700
|
-
/** Creates the
|
|
1933
|
+
/** Creates the body of a generated chapter. @defaultValue `() => ''` */
|
|
1701
1934
|
defaultChapterBody?: (index: number) => string;
|
|
1702
1935
|
}
|
|
1703
1936
|
/** Return value of {@link useManuscriptDraft}. */
|
|
1704
1937
|
interface UseManuscriptDraftReturn {
|
|
1705
1938
|
/** Current chapters, in reading order. */
|
|
1706
|
-
chapters:
|
|
1939
|
+
chapters: readonly ManuscriptChapter$1[];
|
|
1707
1940
|
/** Index of the chapter currently being edited. */
|
|
1708
|
-
|
|
1941
|
+
selectedChapterIndex: number;
|
|
1709
1942
|
/** Selects a chapter, clamped to the chapter range. */
|
|
1710
|
-
|
|
1943
|
+
setSelectedChapterIndex(index: number): void;
|
|
1711
1944
|
/**
|
|
1712
1945
|
* Replaces every chapter; an empty list becomes one generated chapter. The
|
|
1713
1946
|
* selected chapter is kept by id when it survives.
|
|
1714
1947
|
*/
|
|
1715
|
-
setChapters(chapters:
|
|
1948
|
+
setChapters(chapters: readonly ManuscriptChapter$1[]): void;
|
|
1716
1949
|
/** Merges `patch` into the chapter at `index`. */
|
|
1717
|
-
|
|
1718
|
-
/**
|
|
1719
|
-
|
|
1950
|
+
updateChapter(index: number, patch: Partial<ManuscriptChapter$1>): void;
|
|
1951
|
+
/**
|
|
1952
|
+
* Appends a chapter and selects it. Omitted fields are generated: a unique
|
|
1953
|
+
* id, and the title and body of `defaultChapterTitle` / `defaultChapterBody`.
|
|
1954
|
+
*/
|
|
1955
|
+
addChapter(chapter?: Partial<ManuscriptChapter$1>): void;
|
|
1720
1956
|
/** Removes the chapter at `index`; the last remaining chapter is never removed. */
|
|
1721
1957
|
removeChapter(index: number): void;
|
|
1722
1958
|
/** Moves the chapter at `from` to `to`, keeping the same chapter selected. */
|
|
@@ -1733,16 +1969,20 @@ interface UseManuscriptDraftReturn {
|
|
|
1733
1969
|
* patching individual chapters, plus a debounced autosave hook that fires
|
|
1734
1970
|
* `onAutosave` whenever the chapter list settles.
|
|
1735
1971
|
*/
|
|
1736
|
-
declare function useManuscriptDraft<TAutosave =
|
|
1972
|
+
declare function useManuscriptDraft<TAutosave = ManuscriptChapter$1[]>(options?: UseManuscriptDraftOptions<TAutosave>): UseManuscriptDraftReturn;
|
|
1737
1973
|
|
|
1738
1974
|
/** Options for {@link useManuscriptLayout}. */
|
|
1739
1975
|
interface UseManuscriptLayoutOptions {
|
|
1976
|
+
/** The chapter to lay out; `null` lays nothing out. */
|
|
1977
|
+
chapter: ManuscriptChapter | null;
|
|
1978
|
+
/** The reading surface the pages are sized against. */
|
|
1979
|
+
surface: RefObject<HTMLElement | null>;
|
|
1740
1980
|
/** Manuscript notation dialect. @defaultValue `'mejiro'` */
|
|
1741
1981
|
dialect?: ManuscriptDialect;
|
|
1742
1982
|
/** Observe the surface element for size changes and re-flow. @defaultValue true */
|
|
1743
1983
|
enableResize?: boolean;
|
|
1744
1984
|
/** Debounce window (ms) applied to size-triggered re-flows. @defaultValue 120 */
|
|
1745
|
-
|
|
1985
|
+
resizeDebounceMs?: number;
|
|
1746
1986
|
/**
|
|
1747
1987
|
* Capture the reading position from the outgoing layout, just before a
|
|
1748
1988
|
* **reflow** (non-blank) re-layout replaces it. The anchor is held in
|
|
@@ -1765,30 +2005,11 @@ interface UseManuscriptLayoutOptions {
|
|
|
1765
2005
|
*/
|
|
1766
2006
|
onError?: (error: Error) => void;
|
|
1767
2007
|
}
|
|
1768
|
-
/** Options for {@link UseManuscriptLayoutReturn.recompute}. */
|
|
1769
|
-
interface ManuscriptRecomputeOptions {
|
|
1770
|
-
/**
|
|
1771
|
-
* Blank the current layout while the new one is computed. Use for content
|
|
1772
|
-
* changes (chapter swaps); skip for size changes so the previous spread stays
|
|
1773
|
-
* visible until the re-flow completes (no flicker).
|
|
1774
|
-
* @defaultValue true
|
|
1775
|
-
*/
|
|
1776
|
-
blank?: boolean;
|
|
1777
|
-
}
|
|
1778
|
-
/** Page dimensions returned by {@link MejiroBook.computePageSize}. */
|
|
1779
|
-
interface ManuscriptPageDimensions {
|
|
1780
|
-
/** Width of one page, in CSS pixels. */
|
|
1781
|
-
pageWidth: number;
|
|
1782
|
-
/** Height of one page, in CSS pixels. */
|
|
1783
|
-
pageHeight: number;
|
|
1784
|
-
/** Height of the text area inside a page, in CSS pixels. */
|
|
1785
|
-
contentHeight: number;
|
|
1786
|
-
}
|
|
1787
2008
|
/** Return value of {@link useManuscriptLayout}. */
|
|
1788
2009
|
interface UseManuscriptLayoutReturn {
|
|
1789
2010
|
/** Current layout, or `null` before the first computation. */
|
|
1790
2011
|
layout: ChapterLayout | null;
|
|
1791
|
-
/** Page width in pixels. */
|
|
2012
|
+
/** Page width in pixels, as {@link MejiroBook.fitPageSize} measured it. */
|
|
1792
2013
|
pageWidth: number;
|
|
1793
2014
|
/** Page height in pixels. */
|
|
1794
2015
|
pageHeight: number;
|
|
@@ -1796,11 +2017,16 @@ interface UseManuscriptLayoutReturn {
|
|
|
1796
2017
|
contentHeight: number;
|
|
1797
2018
|
/** Most recent layout time (ms). */
|
|
1798
2019
|
elapsedMs: number;
|
|
2020
|
+
/**
|
|
2021
|
+
* Failure of the most recent layout of the current source, whichever path
|
|
2022
|
+
* started it; `null` once a layout succeeds or the source changes.
|
|
2023
|
+
*/
|
|
2024
|
+
error: Error | null;
|
|
1799
2025
|
/**
|
|
1800
2026
|
* Force a fresh layout computation. A failure goes to `onError` when one is
|
|
1801
2027
|
* supplied; otherwise the returned promise rejects.
|
|
1802
2028
|
*/
|
|
1803
|
-
recompute: (opts?:
|
|
2029
|
+
recompute: (opts?: ChapterLayoutRecomputeOptions) => Promise<void>;
|
|
1804
2030
|
/**
|
|
1805
2031
|
* Anchor captured by `capturePosition` before the most recent reflow,
|
|
1806
2032
|
* awaiting restoration into the new layout. `restorePosition`, when given,
|
|
@@ -1820,7 +2046,8 @@ interface UseManuscriptLayoutReturn {
|
|
|
1820
2046
|
* Re-layouts whenever the chapter's id, title or body, `dialect`, or `book`
|
|
1821
2047
|
* change; a new chapter object with the same content does not. The surface is
|
|
1822
2048
|
* observed with {@link ResizeObserver}; size changes trigger a full re-layout
|
|
1823
|
-
* so pagination stays correct after non-trivial container changes.
|
|
2049
|
+
* so pagination stays correct after non-trivial container changes. While the
|
|
2050
|
+
* surface measures zero wide or high, nothing is measured or laid out.
|
|
1824
2051
|
*
|
|
1825
2052
|
* A size-driven re-layout keeps the previous layout on screen while the new one
|
|
1826
2053
|
* is computed (no blank flash) and yields a new {@link ChapterLayout} object,
|
|
@@ -1830,8 +2057,11 @@ interface UseManuscriptLayoutReturn {
|
|
|
1830
2057
|
* {@link UseManuscriptLayoutOptions.restorePosition} and
|
|
1831
2058
|
* {@link UseManuscriptLayoutReturn.pendingRestore}, identically in the Vue
|
|
1832
2059
|
* composable.
|
|
2060
|
+
*
|
|
2061
|
+
* @param book - The book instance to lay out with.
|
|
2062
|
+
* @param options - The chapter and surface to lay out, plus behavior overrides.
|
|
1833
2063
|
*/
|
|
1834
|
-
declare function useManuscriptLayout(book: MejiroBook,
|
|
2064
|
+
declare function useManuscriptLayout(book: MejiroBook, options: UseManuscriptLayoutOptions): UseManuscriptLayoutReturn;
|
|
1835
2065
|
|
|
1836
2066
|
/** Options for {@link useMejiroBook}. */
|
|
1837
2067
|
interface UseMejiroBookOptions {
|
|
@@ -1847,7 +2077,7 @@ interface UseMejiroBookOptions {
|
|
|
1847
2077
|
/**
|
|
1848
2078
|
* Called when applying options to the book fails. When supplied, failures are
|
|
1849
2079
|
* reported here and the promise returned by
|
|
1850
|
-
* {@link UseMejiroBookReturn.
|
|
2080
|
+
* {@link UseMejiroBookReturn.updateOptions} resolves instead of rejecting, so
|
|
1851
2081
|
* fire-and-forget callers cannot leave an unhandled rejection behind.
|
|
1852
2082
|
*/
|
|
1853
2083
|
onError?: (error: Error) => void;
|
|
@@ -1862,26 +2092,31 @@ interface UseMejiroBookReturn {
|
|
|
1862
2092
|
*/
|
|
1863
2093
|
options: Readonly<BookOptions>;
|
|
1864
2094
|
/**
|
|
1865
|
-
*
|
|
1866
|
-
* updated synchronously; the returned promise resolves once
|
|
1867
|
-
* {@link MejiroBook.
|
|
2095
|
+
* Merges `patch` into the options of the underlying book and the snapshot.
|
|
2096
|
+
* The snapshot is updated synchronously; the returned promise resolves once
|
|
2097
|
+
* {@link MejiroBook.updateOptions} has propagated font / size changes (which
|
|
1868
2098
|
* complete only after the font has loaded).
|
|
1869
2099
|
*/
|
|
1870
|
-
|
|
2100
|
+
updateOptions: (patch: BookOptionsPatch) => Promise<void>;
|
|
1871
2101
|
}
|
|
1872
2102
|
/**
|
|
1873
2103
|
* React hook that owns a {@link MejiroBook} instance and exposes its
|
|
1874
|
-
* options as React state.
|
|
1875
|
-
* option changes must go through {@link UseMejiroBookReturn.setOptions}
|
|
1876
|
-
* (e.g. via the `MejiroReader` imperative handle).
|
|
2104
|
+
* options as React state.
|
|
1877
2105
|
*
|
|
1878
|
-
*
|
|
1879
|
-
*
|
|
2106
|
+
* The book is created once on mount from `options`. Afterwards, a change to
|
|
2107
|
+
* the content of a key {@link MejiroBook.updateOptions} accepts — compared by
|
|
2108
|
+
* value, so an object literal recreated every render is fine — is applied like
|
|
2109
|
+
* an {@link UseMejiroBookReturn.updateOptions} call; without `onError`, a
|
|
2110
|
+
* failure of such an application goes to `console.warn`. A change to a
|
|
2111
|
+
* construction-time key (`strictFontCheck`, `analyzer`, `pageSize`, …) is
|
|
2112
|
+
* ignored and the book is not recreated; give the component a new React `key`
|
|
2113
|
+
* to start over with a new book.
|
|
2114
|
+
*
|
|
2115
|
+
* @param options - Book options; read in full on mount, and for their runtime keys on every render.
|
|
2116
|
+
* @param hookOptions - Behavior overrides (debouncing, error reporting).
|
|
1880
2117
|
*/
|
|
1881
|
-
declare function useMejiroBook(
|
|
2118
|
+
declare function useMejiroBook(options: BookOptions, hookOptions?: UseMejiroBookOptions): UseMejiroBookReturn;
|
|
1882
2119
|
|
|
1883
|
-
/** Minimal storage interface required by {@link useReadingPosition}. */
|
|
1884
|
-
type ReadingPositionStorage = MejiroStorage;
|
|
1885
2120
|
/** Options for {@link useReadingPosition}. */
|
|
1886
2121
|
interface UseReadingPositionOptions {
|
|
1887
2122
|
/** Storage key — usually scoped per-book (e.g. `mejiro:position:${bookId}`). */
|
|
@@ -1890,24 +2125,34 @@ interface UseReadingPositionOptions {
|
|
|
1890
2125
|
* Storage backend. Defaults to `window.localStorage` when available.
|
|
1891
2126
|
* SSR consumers can omit this and the hook will fall back to in-memory.
|
|
1892
2127
|
*/
|
|
1893
|
-
storage?:
|
|
2128
|
+
storage?: MejiroStorage;
|
|
1894
2129
|
/**
|
|
1895
|
-
* Debounce delay (ms): the latest value is written this long after the last
|
|
2130
|
+
* Debounce delay (ms): the latest value is written this long after the last
|
|
2131
|
+
* change. A pending write is flushed on page hide, key change and unmount.
|
|
2132
|
+
* @defaultValue 250
|
|
1896
2133
|
*/
|
|
1897
|
-
|
|
2134
|
+
debounceMs?: number;
|
|
1898
2135
|
/**
|
|
1899
2136
|
* Called immediately after `save()` (with the new anchor) or `clear()`
|
|
1900
2137
|
* (with `null`). Use to mirror the position to a server alongside the
|
|
1901
2138
|
* local `storage`. Not invoked on initial hydration or `key` changes.
|
|
1902
2139
|
*/
|
|
1903
|
-
|
|
2140
|
+
onPositionChange?: (next: ReadingAnchor$1 | null) => void;
|
|
2141
|
+
/**
|
|
2142
|
+
* Receives a storage failure: `storage-read-failed` or `storage-corrupt` when
|
|
2143
|
+
* hydrating (the position starts as `null`, and the stored value is left
|
|
2144
|
+
* alone until the next `save()`), `storage-write-failed` when a write or
|
|
2145
|
+
* removal throws (the in-memory position is kept). Without it the error goes
|
|
2146
|
+
* to `console.warn`.
|
|
2147
|
+
*/
|
|
2148
|
+
onError?: (error: MejiroError) => void;
|
|
1904
2149
|
}
|
|
1905
2150
|
/** Return value of {@link useReadingPosition}. */
|
|
1906
2151
|
interface UseReadingPositionReturn {
|
|
1907
2152
|
/** Most recently persisted position, or `null` if none. */
|
|
1908
|
-
position:
|
|
1909
|
-
/** Persist a new position (debounced by `
|
|
1910
|
-
save(next:
|
|
2153
|
+
position: ReadingAnchor$1 | null;
|
|
2154
|
+
/** Persist a new position (debounced by `debounceMs`). */
|
|
2155
|
+
save(next: ReadingAnchor$1): void;
|
|
1911
2156
|
/** Remove the persisted position. */
|
|
1912
2157
|
clear(): void;
|
|
1913
2158
|
}
|
|
@@ -1934,73 +2179,11 @@ interface UseReadingPositionReturn {
|
|
|
1934
2179
|
* }, [save]);
|
|
1935
2180
|
* ```
|
|
1936
2181
|
*
|
|
1937
|
-
*
|
|
1938
|
-
*
|
|
1939
|
-
*
|
|
2182
|
+
* Every stored layout {@link parseReadingPosition} reads is accepted; one
|
|
2183
|
+
* that names only a chapter and a spread resumes at the start of the chapter,
|
|
2184
|
+
* because a spread index does not survive reflow.
|
|
1940
2185
|
*/
|
|
1941
2186
|
declare function useReadingPosition(options: UseReadingPositionOptions): UseReadingPositionReturn;
|
|
1942
2187
|
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
/** Enable ArrowLeft/ArrowRight navigation. @defaultValue true */
|
|
1946
|
-
enableKeyboard?: boolean;
|
|
1947
|
-
/** Page-turn animation duration in ms. @defaultValue 180 */
|
|
1948
|
-
turnDuration?: number;
|
|
1949
|
-
/**
|
|
1950
|
-
* Show one page at a time: the navigation index then counts pages instead
|
|
1951
|
-
* of two-page spreads. Toggling it converts the index so the page on
|
|
1952
|
-
* screen stays visible. @defaultValue false
|
|
1953
|
-
*/
|
|
1954
|
-
single?: boolean;
|
|
1955
|
-
/** Called when the spread index changes (after the turn animation midpoint). */
|
|
1956
|
-
onChange?: (spreadIdx: number) => void;
|
|
1957
|
-
}
|
|
1958
|
-
/** Return value of {@link useSpread}. */
|
|
1959
|
-
interface UseSpreadReturn {
|
|
1960
|
-
/** Current navigation index: a page index in single mode, a spread index otherwise. */
|
|
1961
|
-
spreadIdx: number;
|
|
1962
|
-
/** Layout spread holding the visible page(s), or `null` until the layout is ready. */
|
|
1963
|
-
spread: SpreadResult | null;
|
|
1964
|
-
/** First page shown, in reading order. */
|
|
1965
|
-
firstPage: number;
|
|
1966
|
-
/** Index of {@link UseSpreadReturn.spread} in the layout (`ChapterLayout.getSpread`). */
|
|
1967
|
-
layoutSpreadIdx: number;
|
|
1968
|
-
/** Side of {@link UseSpreadReturn.spread} shown in single mode; `null` in double mode. */
|
|
1969
|
-
singleSide: 'right' | 'left' | null;
|
|
1970
|
-
/** Total number of pages, as of {@link UseSpreadReturn.spread}. */
|
|
1971
|
-
totalPages: number;
|
|
1972
|
-
/** Number of navigation positions: pages in single mode, two-page spreads otherwise. */
|
|
1973
|
-
totalSpreads: number;
|
|
1974
|
-
/** Whether the turn animation is currently in flight. */
|
|
1975
|
-
turning: boolean;
|
|
1976
|
-
/** Advance one position (page or spread) forward. */
|
|
1977
|
-
next: () => void;
|
|
1978
|
-
/** Go back one position. */
|
|
1979
|
-
prev: () => void;
|
|
1980
|
-
/** Jump to an arbitrary navigation index (clamped). */
|
|
1981
|
-
goTo: (index: number) => void;
|
|
1982
|
-
/**
|
|
1983
|
-
* Set the navigation index immediately, with no page-turn animation, clamped
|
|
1984
|
-
* to `[0, totalSpreads − 1]`. Use to restore a reading position after a reflow
|
|
1985
|
-
* re-layout (where an animated {@link goTo} would briefly flash spread 0).
|
|
1986
|
-
*/
|
|
1987
|
-
setSpread: (index: number) => void;
|
|
1988
|
-
/** Navigation index that shows the given page index. */
|
|
1989
|
-
indexOfPage: (pageIdx: number) => number;
|
|
1990
|
-
/**
|
|
1991
|
-
* Anchor at the start of the text shown at navigation index `index`. A page an
|
|
1992
|
-
* image blocks entirely holds no text, so the anchor then comes from the next
|
|
1993
|
-
* page that does, even past `index`; `null` when no page from there on holds text.
|
|
1994
|
-
*/
|
|
1995
|
-
anchorAt: (index: number) => InChapterAnchor | null;
|
|
1996
|
-
/** Manually refresh `spread` from `layout` at the current index. */
|
|
1997
|
-
refresh: () => void;
|
|
1998
|
-
}
|
|
1999
|
-
/**
|
|
2000
|
-
* React hook that tracks the current spread index for a chapter layout
|
|
2001
|
-
* and exposes navigation helpers with an optional page-turn animation.
|
|
2002
|
-
*/
|
|
2003
|
-
declare function useSpread(layout: ChapterLayout | null, options?: UseSpreadOptions): UseSpreadReturn;
|
|
2004
|
-
|
|
2005
|
-
export { MejiroChapterNav, MejiroDropZone, MejiroEditor, MejiroI18nProvider, MejiroImageOverlay, MejiroManuscriptEditor, MejiroNotationHighlighter, MejiroPage, MejiroPageIndicator, MejiroPageView, MejiroReader, MejiroScrollView, MejiroSelectionLayer, MejiroSettingsPanel, MejiroShelf, MejiroSpread, MejiroStats, MejiroToc, format, resolveMessages, useAnnotations, useChapterLayout, useEditableEpub, useEpub, useEpubProject, useI18n, useImageOverlay, useLibrary, useManuscriptDraft, useManuscriptLayout, useMejiroBook, useMultiImageOverlay, useReadingPosition, useSpread };
|
|
2006
|
-
export type { AnnotationsStorage, EpubProjectChapterDraft, ImageRect, ManuscriptAutosaveDraft, ManuscriptEditorChapter, ManuscriptPageDimensions, ManuscriptPreviewProps, ManuscriptRecomputeOptions, MejiroChapterNavMode, MejiroChapterNavProps, MejiroChapterNavVariant, MejiroDropZoneProps, MejiroEditorProps, MejiroExportPolicy, MejiroImageOverlayProps, MejiroManuscriptEditorProps, MejiroNotationHighlighterProps, MejiroPageIndicatorProps, MejiroPageProps, MejiroPageViewProps, MejiroReaderCommonProps, MejiroReaderControlledProps, MejiroReaderEventMap, MejiroReaderFileProps, MejiroReaderFit, MejiroReaderHandle, MejiroReaderManuscriptProps, MejiroReaderMode, MejiroReaderProps, MejiroReaderSettingsSlot, MejiroReaderUrlProps, MejiroScrollViewProps, MejiroSelectionLayerProps, MejiroSettingsPanelProps, MejiroShelfProps, MejiroSpreadMode, MejiroSpreadProps, MejiroStatsProps, MejiroTheme, MejiroThemeName, MejiroTocProps, MultiImageItem, PageDimensions, ReadingPosition, ReadingPositionStorage, RecomputeOptions, UseAnnotationsOptions, UseAnnotationsReturn, UseChapterLayoutOptions, UseChapterLayoutReturn, UseEditableEpubOptions, UseEditableEpubReturn, UseEpubOptions, UseEpubProjectOptions, UseEpubProjectReturn, UseEpubReturn, UseI18nOptions, UseImageOverlayOptions, UseImageOverlayReturn, UseLibraryOptions, UseLibraryReturn, UseManuscriptDraftOptions, UseManuscriptDraftReturn, UseManuscriptLayoutOptions, UseManuscriptLayoutReturn, UseMejiroBookOptions, UseMejiroBookReturn, UseMultiImageOverlayOptions, UseMultiImageOverlayReturn, UseReadingPositionOptions, UseReadingPositionReturn, UseSpreadOptions, UseSpreadReturn, VolumeInfo };
|
|
2188
|
+
export { MejiroChapterNav, MejiroDropZone, MejiroEditor, MejiroI18nProvider, MejiroImagePlaceholder, MejiroManuscriptEditor, MejiroNotationHighlighter, MejiroPage, MejiroPageIndicator, MejiroPageView, MejiroReader, MejiroScrollView, MejiroSelectionLayer, MejiroSettingsPanel, MejiroShelf, MejiroSpread, MejiroStats, MejiroToc, useAnnotations, useChapterLayout, useEditableEpub, useEpub, useEpubProject, useI18n, useImageOverlay, useLibrary, useManuscriptDraft, useManuscriptLayout, useMejiroBook, useReadingPosition, useSpread };
|
|
2189
|
+
export type { ChapterLayoutRecomputeOptions, ExportPolicy, FetchEpubOptions, GoToOptions, ManuscriptAutosaveDraft, ManuscriptPreviewProps, MejiroChapterNavMode, MejiroChapterNavProps, MejiroChapterNavVariant, MejiroDropZoneProps, MejiroEditorProps, MejiroI18nProviderProps, MejiroImagePlaceholderProps, MejiroManuscriptEditorProps, MejiroNotationHighlighterProps, MejiroPageIndicatorProps, MejiroPageProps, MejiroPageViewProps, MejiroReaderChapterFinishedEvent, MejiroReaderCommonProps, MejiroReaderEventMap, MejiroReaderFit, MejiroReaderHandle, MejiroReaderManuscriptProps, MejiroReaderMode, MejiroReaderParsedProps, MejiroReaderPickerProps, MejiroReaderProps, MejiroReaderSettingsSlot, MejiroReaderSpreadIndexChangeEvent, MejiroReaderTurnEndEvent, MejiroReaderTurnStartEvent, MejiroReaderUrlProps, MejiroScrollViewProps, MejiroSelectionLayerProps, MejiroSettingsPanelProps, MejiroShelfProps, MejiroSpreadMode, MejiroSpreadProps, MejiroStatsProps, MejiroTheme, MejiroThemeName, MejiroTocProps, MultiImageItem, ReaderAnnotation, ReadingAnchorRange, ResolvedSpreadMode, SelectionRect, SpreadPosition, UseAnnotationsOptions, UseAnnotationsReturn, UseChapterLayoutOptions, UseChapterLayoutReturn, UseEditableEpubOptions, UseEditableEpubReturn, UseEpubOptions, UseEpubProjectOptions, UseEpubProjectReturn, UseEpubReturn, UseI18nOptions, UseImageOverlayOptions, UseImageOverlayReturn, UseLibraryOptions, UseLibraryReturn, UseManuscriptDraftOptions, UseManuscriptDraftReturn, UseManuscriptLayoutOptions, UseManuscriptLayoutReturn, UseMejiroBookOptions, UseMejiroBookReturn, UseReadingPositionOptions, UseReadingPositionReturn, UseSpreadOptions, UseSpreadReturn, VolumeInfo };
|