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