@libraz/mejiro-react 0.6.0 → 0.7.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/dist/index.d.ts +216 -366
- package/dist/index.js +626 -663
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -1,134 +1,13 @@
|
|
|
1
1
|
// src/i18n.tsx
|
|
2
|
+
import {
|
|
3
|
+
enMessages,
|
|
4
|
+
formatMessage,
|
|
5
|
+
messageCatalogs,
|
|
6
|
+
resolveMessages as resolveCoreMessages
|
|
7
|
+
} from "@libraz/mejiro";
|
|
2
8
|
import { createContext, useContext, useMemo } from "react";
|
|
9
|
+
import { enMessages as enMessages2, jaMessages } from "@libraz/mejiro";
|
|
3
10
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
var enMessages = {
|
|
5
|
-
logoSubtitle: "Vertical Reader",
|
|
6
|
-
openButton: "Open",
|
|
7
|
-
settingsButton: "Settings",
|
|
8
|
-
imageButton: "Image",
|
|
9
|
-
imageRemoveButton: "Remove image",
|
|
10
|
-
loading: "Loading...",
|
|
11
|
-
prevSpread: "Previous spread",
|
|
12
|
-
nextSpread: "Next spread",
|
|
13
|
-
settingsFont: "Font",
|
|
14
|
-
settingsSize: "Size",
|
|
15
|
-
settingsSizeDown: "Decrease font size",
|
|
16
|
-
settingsSizeUp: "Increase font size",
|
|
17
|
-
settingsLayout: "Layout",
|
|
18
|
-
settingsKinsoku: "Kinsoku",
|
|
19
|
-
settingsHanging: "Hanging",
|
|
20
|
-
settingsLineSpacing: "Line spacing",
|
|
21
|
-
settingsStrict: "Strict",
|
|
22
|
-
settingsLoose: "Loose",
|
|
23
|
-
toggleOn: "On",
|
|
24
|
-
toggleOff: "Off",
|
|
25
|
-
dropZoneTitle: "Drop an EPUB here or click to open",
|
|
26
|
-
dropZoneHint: ".epub files only",
|
|
27
|
-
tocTitle: "Contents",
|
|
28
|
-
tocSearchPlaceholder: "Search chapters\u2026",
|
|
29
|
-
tocEmpty: 'No chapters match "{query}".',
|
|
30
|
-
shelfTitle: "Library",
|
|
31
|
-
chapterN: "Chapter {n}",
|
|
32
|
-
spreadAnnouncement: "Spread {spread} of {total}",
|
|
33
|
-
editorPreviewSubtitle: "Editor Preview",
|
|
34
|
-
editorTitle: "EPUB Editor",
|
|
35
|
-
editorNoBookLoaded: "No book loaded",
|
|
36
|
-
editorParagraphs: "Paragraphs",
|
|
37
|
-
editorProofread: "Proofread",
|
|
38
|
-
editorApplyText: "Apply text",
|
|
39
|
-
editorRuby: "Ruby",
|
|
40
|
-
editorRubyHint: "Select base text in the textarea, then type the ruby reading below.",
|
|
41
|
-
editorRubyRange: "Base: {start}-{end} ({count} chars)",
|
|
42
|
-
editorRubyPlaceholder: "furigana",
|
|
43
|
-
editorApplyRuby: "Apply ruby",
|
|
44
|
-
editorImages: "Images",
|
|
45
|
-
editorInsertImageAfterParagraph: "Insert image after paragraph",
|
|
46
|
-
editorExportEpub: "Export EPUB",
|
|
47
|
-
manuscriptPreviewSubtitle: "Manuscript Preview",
|
|
48
|
-
manuscriptTitle: "Manuscript EPUB",
|
|
49
|
-
manuscriptRubyHint: "Use \uFF5C\u6F22\u5B57\u300A\u304B\u3093\u3058\u300B or \u6F22\u5B57\u300A\u304B\u3093\u3058\u300B for ruby.",
|
|
50
|
-
manuscriptMetadata: "Metadata",
|
|
51
|
-
manuscriptChapters: "Chapters",
|
|
52
|
-
manuscriptDraft: "Draft",
|
|
53
|
-
manuscriptChooseCoverImage: "Choose cover image",
|
|
54
|
-
manuscriptDefaultTitle: "New work",
|
|
55
|
-
manuscriptDefaultChapterTitle: "Chapter {n}",
|
|
56
|
-
manuscriptDefaultBody: "This is a ruby example: \uFF5Ckanji\u300Areading\u300B.\n\nPaste your draft here.",
|
|
57
|
-
untitled: "Untitled",
|
|
58
|
-
manuscriptAddChapter: "Add chapter",
|
|
59
|
-
manuscriptRemove: "Remove",
|
|
60
|
-
manuscriptEmphasisDots: "Emphasis dots",
|
|
61
|
-
manuscriptTcy: "Tate-chu-yoko",
|
|
62
|
-
manuscriptEm: "Em",
|
|
63
|
-
manuscriptStrong: "Strong",
|
|
64
|
-
manuscriptReorderHandle: "Reorder {title}"
|
|
65
|
-
};
|
|
66
|
-
var jaMessages = {
|
|
67
|
-
logoSubtitle: "\u7E26\u66F8\u304D\u30EA\u30FC\u30C0\u30FC",
|
|
68
|
-
openButton: "\u958B\u304F",
|
|
69
|
-
settingsButton: "\u8A2D\u5B9A",
|
|
70
|
-
imageButton: "\u753B\u50CF",
|
|
71
|
-
imageRemoveButton: "\u753B\u50CF\u3092\u524A\u9664",
|
|
72
|
-
loading: "\u8AAD\u307F\u8FBC\u307F\u4E2D\u2026",
|
|
73
|
-
prevSpread: "\u524D\u306E\u898B\u958B\u304D",
|
|
74
|
-
nextSpread: "\u6B21\u306E\u898B\u958B\u304D",
|
|
75
|
-
settingsFont: "\u30D5\u30A9\u30F3\u30C8",
|
|
76
|
-
settingsSize: "\u30B5\u30A4\u30BA",
|
|
77
|
-
settingsSizeDown: "\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA\u3092\u4E0B\u3052\u308B",
|
|
78
|
-
settingsSizeUp: "\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA\u3092\u4E0A\u3052\u308B",
|
|
79
|
-
settingsLayout: "\u30EC\u30A4\u30A2\u30A6\u30C8",
|
|
80
|
-
settingsKinsoku: "\u7981\u5247",
|
|
81
|
-
settingsHanging: "\u3076\u3089\u4E0B\u3052",
|
|
82
|
-
settingsLineSpacing: "\u884C\u9593",
|
|
83
|
-
settingsStrict: "\u53B3\u683C",
|
|
84
|
-
settingsLoose: "\u7DE9\u548C",
|
|
85
|
-
toggleOn: "\u30AA\u30F3",
|
|
86
|
-
toggleOff: "\u30AA\u30D5",
|
|
87
|
-
dropZoneTitle: "EPUB \u3092\u30C9\u30ED\u30C3\u30D7\u307E\u305F\u306F\u30AF\u30EA\u30C3\u30AF\u3067\u958B\u304F",
|
|
88
|
-
dropZoneHint: ".epub \u30D5\u30A1\u30A4\u30EB\u306E\u307F",
|
|
89
|
-
tocTitle: "\u76EE\u6B21",
|
|
90
|
-
tocSearchPlaceholder: "\u7AE0\u3092\u691C\u7D22\u2026",
|
|
91
|
-
tocEmpty: "\u300C{query}\u300D\u306B\u4E00\u81F4\u3059\u308B\u7AE0\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
92
|
-
shelfTitle: "\u672C\u68DA",
|
|
93
|
-
chapterN: "\u7B2C{n}\u7AE0",
|
|
94
|
-
spreadAnnouncement: "{total}\u898B\u958B\u304D\u4E2D{spread}\u898B\u958B\u304D\u76EE",
|
|
95
|
-
editorPreviewSubtitle: "\u7DE8\u96C6\u30D7\u30EC\u30D3\u30E5\u30FC",
|
|
96
|
-
editorTitle: "EPUB \u30A8\u30C7\u30A3\u30BF\u30FC",
|
|
97
|
-
editorNoBookLoaded: "\u672C\u304C\u8AAD\u307F\u8FBC\u307E\u308C\u3066\u3044\u307E\u305B\u3093",
|
|
98
|
-
editorParagraphs: "\u6BB5\u843D",
|
|
99
|
-
editorProofread: "\u6821\u6B63",
|
|
100
|
-
editorApplyText: "\u672C\u6587\u3092\u9069\u7528",
|
|
101
|
-
editorRuby: "\u30EB\u30D3",
|
|
102
|
-
editorRubyHint: "\u30C6\u30AD\u30B9\u30C8\u30A8\u30EA\u30A2\u3067\u89AA\u6587\u5B57\u3092\u9078\u629E\u3057\u3066\u304B\u3089\u3001\u4E0B\u306B\u30EB\u30D3\u3092\u5165\u529B\u3057\u307E\u3059\u3002",
|
|
103
|
-
editorRubyRange: "\u89AA\u6587\u5B57: {start}-{end}\uFF08{count}\u6587\u5B57\uFF09",
|
|
104
|
-
editorRubyPlaceholder: "\u3075\u308A\u304C\u306A",
|
|
105
|
-
editorApplyRuby: "\u30EB\u30D3\u3092\u9069\u7528",
|
|
106
|
-
editorImages: "\u753B\u50CF",
|
|
107
|
-
editorInsertImageAfterParagraph: "\u6BB5\u843D\u306E\u5F8C\u306B\u753B\u50CF\u3092\u633F\u5165",
|
|
108
|
-
editorExportEpub: "EPUB \u3092\u66F8\u304D\u51FA\u3059",
|
|
109
|
-
manuscriptPreviewSubtitle: "\u539F\u7A3F\u30D7\u30EC\u30D3\u30E5\u30FC",
|
|
110
|
-
manuscriptTitle: "\u539F\u7A3F EPUB",
|
|
111
|
-
manuscriptRubyHint: "\u30EB\u30D3\u306B\u306F \uFF5C\u6F22\u5B57\u300A\u304B\u3093\u3058\u300B \u307E\u305F\u306F \u6F22\u5B57\u300A\u304B\u3093\u3058\u300B \u3092\u4F7F\u3044\u307E\u3059\u3002",
|
|
112
|
-
manuscriptMetadata: "\u30E1\u30BF\u30C7\u30FC\u30BF",
|
|
113
|
-
manuscriptChapters: "\u7AE0",
|
|
114
|
-
manuscriptDraft: "\u539F\u7A3F",
|
|
115
|
-
manuscriptChooseCoverImage: "\u8868\u7D19\u753B\u50CF\u3092\u9078\u629E",
|
|
116
|
-
manuscriptDefaultTitle: "\u65B0\u3057\u3044\u4F5C\u54C1",
|
|
117
|
-
manuscriptDefaultChapterTitle: "\u7B2C{n}\u8A71",
|
|
118
|
-
manuscriptDefaultBody: "\u3053\u308C\u306F\uFF5C\u6F22\u5B57\u300A\u304B\u3093\u3058\u300B\u306E\u30EB\u30D3\u4F8B\u3067\u3059\u3002\n\n\u672C\u6587\u3092\u3053\u3053\u306B\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002",
|
|
119
|
-
untitled: "\u7121\u984C",
|
|
120
|
-
manuscriptAddChapter: "\u7AE0\u3092\u8FFD\u52A0",
|
|
121
|
-
manuscriptRemove: "\u524A\u9664",
|
|
122
|
-
manuscriptEmphasisDots: "\u508D\u70B9",
|
|
123
|
-
manuscriptTcy: "\u7E26\u4E2D\u6A2A",
|
|
124
|
-
manuscriptEm: "\u5F37\u8ABF",
|
|
125
|
-
manuscriptStrong: "\u592A\u5B57",
|
|
126
|
-
manuscriptReorderHandle: "{title} \u306E\u9806\u756A\u3092\u5909\u66F4"
|
|
127
|
-
};
|
|
128
|
-
var CATALOGS = {
|
|
129
|
-
en: enMessages,
|
|
130
|
-
ja: jaMessages
|
|
131
|
-
};
|
|
132
11
|
var I18nContext = createContext(enMessages);
|
|
133
12
|
function MejiroI18nProvider({
|
|
134
13
|
locale,
|
|
@@ -136,10 +15,10 @@ function MejiroI18nProvider({
|
|
|
136
15
|
children
|
|
137
16
|
}) {
|
|
138
17
|
const fromContext = useContext(I18nContext);
|
|
139
|
-
const value = useMemo(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
18
|
+
const value = useMemo(
|
|
19
|
+
() => resolveCoreMessages(locale, messages, locale != null ? enMessages : fromContext),
|
|
20
|
+
[locale, messages, fromContext]
|
|
21
|
+
);
|
|
143
22
|
return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
|
|
144
23
|
}
|
|
145
24
|
function useI18n(options = {}) {
|
|
@@ -147,19 +26,14 @@ function useI18n(options = {}) {
|
|
|
147
26
|
const { locale, messages } = options;
|
|
148
27
|
return useMemo(() => {
|
|
149
28
|
if (locale == null && messages == null) return fromContext;
|
|
150
|
-
|
|
151
|
-
return messages ? { ...base, ...messages } : base;
|
|
29
|
+
return resolveCoreMessages(locale, messages, fromContext);
|
|
152
30
|
}, [locale, messages, fromContext]);
|
|
153
31
|
}
|
|
154
32
|
function resolveMessages(locale, overrides) {
|
|
155
|
-
|
|
156
|
-
return overrides ? { ...base, ...overrides } : base;
|
|
33
|
+
return resolveCoreMessages(locale, overrides);
|
|
157
34
|
}
|
|
158
35
|
function format(template, vars) {
|
|
159
|
-
return template
|
|
160
|
-
/\{(\w+)\}/g,
|
|
161
|
-
(_, k) => Object.hasOwn(vars, k) ? String(vars[k]) : `{${k}}`
|
|
162
|
-
);
|
|
36
|
+
return formatMessage(template, vars);
|
|
163
37
|
}
|
|
164
38
|
|
|
165
39
|
// src/MejiroChapterNav.tsx
|
|
@@ -208,7 +82,10 @@ function MejiroChapterNav({
|
|
|
208
82
|
}) })
|
|
209
83
|
] });
|
|
210
84
|
}
|
|
211
|
-
return /* @__PURE__ */ jsx2("div", { className: "mejiro-reader-chapter-nav", children: /* @__PURE__ */ jsx2("select", { value: chapter, onChange: (e) => onChange(Number(e.target.value)), children: epub.chapters.map((ch, i) =>
|
|
85
|
+
return /* @__PURE__ */ jsx2("div", { className: "mejiro-reader-chapter-nav", children: /* @__PURE__ */ jsx2("select", { value: chapter, onChange: (e) => onChange(Number(e.target.value)), children: epub.chapters.map((ch, i) => (
|
|
86
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: chapter titles are not guaranteed unique
|
|
87
|
+
/* @__PURE__ */ jsx2("option", { value: i, children: ch.title ?? format(messages.chapterN, { n: i + 1 }) }, i)
|
|
88
|
+
)) }) });
|
|
212
89
|
}
|
|
213
90
|
|
|
214
91
|
// src/MejiroDropZone.tsx
|
|
@@ -274,7 +151,7 @@ function MejiroDropZone({
|
|
|
274
151
|
|
|
275
152
|
// src/MejiroEditor.tsx
|
|
276
153
|
import { EditableEpub } from "@libraz/mejiro/epub";
|
|
277
|
-
import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef10, useState as useState8 } from "react";
|
|
154
|
+
import { useCallback as useCallback7, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef10, useState as useState8 } from "react";
|
|
278
155
|
|
|
279
156
|
// src/MejiroReader.tsx
|
|
280
157
|
import { DEFAULT_BOOK_OPTIONS, DEFAULT_PAGE_GEOMETRY } from "@libraz/mejiro/book";
|
|
@@ -312,38 +189,36 @@ import {
|
|
|
312
189
|
|
|
313
190
|
// src/MejiroPageView.tsx
|
|
314
191
|
import { normalizeFontFamily } from "@libraz/mejiro/browser";
|
|
315
|
-
import { Fragment as Fragment3 } from "react";
|
|
316
192
|
|
|
317
|
-
// src/
|
|
318
|
-
import {
|
|
319
|
-
|
|
193
|
+
// src/renderInlineNode.tsx
|
|
194
|
+
import {
|
|
195
|
+
segmentToInlineNode
|
|
196
|
+
} from "@libraz/mejiro/render";
|
|
197
|
+
import { createElement, Fragment as Fragment2 } from "react";
|
|
198
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
320
199
|
function renderSegment(segment, key) {
|
|
321
|
-
|
|
322
|
-
case "text":
|
|
323
|
-
return /* @__PURE__ */ jsx4(Fragment2, { children: segment.text }, key);
|
|
324
|
-
case "ruby":
|
|
325
|
-
return /* @__PURE__ */ jsxs4("ruby", { children: [
|
|
326
|
-
segment.base,
|
|
327
|
-
/* @__PURE__ */ jsx4("rt", { children: segment.rubyText })
|
|
328
|
-
] }, key);
|
|
329
|
-
case "emphasis":
|
|
330
|
-
return /* @__PURE__ */ jsx4("span", { className: `mejiro-emphasis mejiro-emphasis--${segment.style}`, children: segment.text }, key);
|
|
331
|
-
case "tcy":
|
|
332
|
-
return /* @__PURE__ */ jsx4("span", { className: "mejiro-tcy", children: segment.text }, key);
|
|
333
|
-
case "em":
|
|
334
|
-
return /* @__PURE__ */ jsx4("em", { children: segment.text }, key);
|
|
335
|
-
case "strong":
|
|
336
|
-
return /* @__PURE__ */ jsx4("strong", { children: segment.text }, key);
|
|
337
|
-
case "link":
|
|
338
|
-
return /* @__PURE__ */ jsx4("a", { href: segment.href, title: segment.title, children: segment.text }, key);
|
|
339
|
-
case "footnote-ref":
|
|
340
|
-
return /* @__PURE__ */ jsx4("a", { className: "mejiro-footnote-ref", href: `#${segment.noteId}`, children: segment.text }, key);
|
|
341
|
-
}
|
|
200
|
+
return renderInlineNode(segmentToInlineNode(segment), key);
|
|
342
201
|
}
|
|
202
|
+
function renderInlineNode(node, key) {
|
|
203
|
+
if (node.type === "text") return /* @__PURE__ */ jsx4(Fragment2, { children: node.text }, key);
|
|
204
|
+
return createElement(
|
|
205
|
+
node.tag,
|
|
206
|
+
{
|
|
207
|
+
key,
|
|
208
|
+
className: node.className,
|
|
209
|
+
href: node.href,
|
|
210
|
+
title: node.title
|
|
211
|
+
},
|
|
212
|
+
node.children.map((child, index) => renderInlineNode(child, `${key}-${index}`))
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/MejiroPage.tsx
|
|
217
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
343
218
|
function renderLine(line, lineIndex) {
|
|
344
219
|
const nodes = [];
|
|
345
220
|
if (lineIndex > 0) {
|
|
346
|
-
nodes.push(/* @__PURE__ */
|
|
221
|
+
nodes.push(/* @__PURE__ */ jsx5("br", {}, `br-${lineIndex}`));
|
|
347
222
|
}
|
|
348
223
|
for (let i = 0; i < line.segments.length; i++) {
|
|
349
224
|
nodes.push(renderSegment(line.segments[i], `${lineIndex}-${i}`));
|
|
@@ -352,7 +227,7 @@ function renderLine(line, lineIndex) {
|
|
|
352
227
|
}
|
|
353
228
|
function MejiroPage({ page, className, style }) {
|
|
354
229
|
const rootClass = className ? `mejiro-page ${className}` : "mejiro-page";
|
|
355
|
-
return /* @__PURE__ */
|
|
230
|
+
return /* @__PURE__ */ jsx5("div", { className: rootClass, style, children: page.paragraphs.map((paragraph, pi) => {
|
|
356
231
|
let paraClass = "mejiro-paragraph";
|
|
357
232
|
if (paragraph.headingLevel != null) {
|
|
358
233
|
paraClass += ` mejiro-paragraph--h${paragraph.headingLevel}`;
|
|
@@ -361,36 +236,13 @@ function MejiroPage({ page, className, style }) {
|
|
|
361
236
|
}
|
|
362
237
|
return (
|
|
363
238
|
// biome-ignore lint/suspicious/noArrayIndexKey: paragraphs have no stable ID
|
|
364
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ jsx5("div", { className: paraClass, children: paragraph.lines.flatMap((line, li) => renderLine(line, li)) }, pi)
|
|
365
240
|
);
|
|
366
241
|
}) });
|
|
367
242
|
}
|
|
368
243
|
|
|
369
244
|
// src/MejiroPageView.tsx
|
|
370
|
-
import { jsx as
|
|
371
|
-
function renderSlotSegment(segment, key) {
|
|
372
|
-
switch (segment.type) {
|
|
373
|
-
case "text":
|
|
374
|
-
return /* @__PURE__ */ jsx5(Fragment3, { children: segment.text }, key);
|
|
375
|
-
case "ruby":
|
|
376
|
-
return /* @__PURE__ */ jsxs5("ruby", { children: [
|
|
377
|
-
segment.base,
|
|
378
|
-
/* @__PURE__ */ jsx5("rt", { children: segment.rubyText })
|
|
379
|
-
] }, key);
|
|
380
|
-
case "emphasis":
|
|
381
|
-
return /* @__PURE__ */ jsx5("span", { className: `mejiro-emphasis mejiro-emphasis--${segment.style}`, children: segment.text }, key);
|
|
382
|
-
case "tcy":
|
|
383
|
-
return /* @__PURE__ */ jsx5("span", { className: "mejiro-tcy", children: segment.text }, key);
|
|
384
|
-
case "em":
|
|
385
|
-
return /* @__PURE__ */ jsx5("em", { children: segment.text }, key);
|
|
386
|
-
case "strong":
|
|
387
|
-
return /* @__PURE__ */ jsx5("strong", { children: segment.text }, key);
|
|
388
|
-
case "link":
|
|
389
|
-
return /* @__PURE__ */ jsx5("a", { href: segment.href, title: segment.title, children: segment.text }, key);
|
|
390
|
-
case "footnote-ref":
|
|
391
|
-
return /* @__PURE__ */ jsx5("a", { className: "mejiro-footnote-ref", href: `#${segment.noteId}`, children: segment.text }, key);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
245
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
394
246
|
function MejiroPageView({
|
|
395
247
|
result,
|
|
396
248
|
fontFamily,
|
|
@@ -402,7 +254,7 @@ function MejiroPageView({
|
|
|
402
254
|
if (result.hasImages || slotMode) {
|
|
403
255
|
const rootClass = className ? `mejiro-page-slots ${className}` : "mejiro-page-slots";
|
|
404
256
|
const fontFamilyCss = fontFamily != null ? normalizeFontFamily(fontFamily) : void 0;
|
|
405
|
-
return /* @__PURE__ */
|
|
257
|
+
return /* @__PURE__ */ jsx6("div", { className: rootClass, style: { position: "relative", ...style }, children: result.lines.map((line, i) => {
|
|
406
258
|
const slot = result.slots[i];
|
|
407
259
|
if (!slot || slot.height <= 0) return null;
|
|
408
260
|
const colStyle = {
|
|
@@ -420,15 +272,15 @@ function MejiroPageView({
|
|
|
420
272
|
};
|
|
421
273
|
return (
|
|
422
274
|
// biome-ignore lint/suspicious/noArrayIndexKey: lines have no stable ID
|
|
423
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ jsx6("div", { style: colStyle, children: line.segments.map((seg, si) => renderSegment(seg, `${i}-${si}`)) }, i)
|
|
424
276
|
);
|
|
425
277
|
}) });
|
|
426
278
|
}
|
|
427
|
-
return /* @__PURE__ */
|
|
279
|
+
return /* @__PURE__ */ jsx6(MejiroPage, { page: result.page, className, style });
|
|
428
280
|
}
|
|
429
281
|
|
|
430
282
|
// src/MejiroScrollView.tsx
|
|
431
|
-
import { jsx as
|
|
283
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
432
284
|
function MejiroScrollView({
|
|
433
285
|
layout,
|
|
434
286
|
pageWidth,
|
|
@@ -445,10 +297,12 @@ function MejiroScrollView({
|
|
|
445
297
|
const pageRefs = useRef2([]);
|
|
446
298
|
const onVisiblePageChangeRef = useRef2(onVisiblePageChange);
|
|
447
299
|
onVisiblePageChangeRef.current = onVisiblePageChange;
|
|
300
|
+
const programmaticScrollRef = useRef2(false);
|
|
448
301
|
const pages = useMemo2(() => {
|
|
449
302
|
const total = layout.totalPages;
|
|
450
303
|
return Array.from({ length: total }, (_, i) => layout.getPage(i));
|
|
451
304
|
}, [layout]);
|
|
305
|
+
const pageCount = pages.length;
|
|
452
306
|
const useSlot = true;
|
|
453
307
|
const contentStyle = { height: contentHeight };
|
|
454
308
|
if (fontFamily) contentStyle.fontFamily = normalizeFontFamily2(fontFamily);
|
|
@@ -457,6 +311,7 @@ function MejiroScrollView({
|
|
|
457
311
|
useEffect(() => {
|
|
458
312
|
const container = containerRef.current;
|
|
459
313
|
if (!container) return;
|
|
314
|
+
if (pageCount === 0) return;
|
|
460
315
|
if (typeof IntersectionObserver === "undefined") return;
|
|
461
316
|
let mostVisibleIdx = -1;
|
|
462
317
|
let mostVisibleRatio = 0;
|
|
@@ -475,7 +330,12 @@ function MejiroScrollView({
|
|
|
475
330
|
}
|
|
476
331
|
}
|
|
477
332
|
}
|
|
478
|
-
if (mostVisibleIdx >= 0)
|
|
333
|
+
if (mostVisibleIdx >= 0) {
|
|
334
|
+
onVisiblePageChangeRef.current?.(
|
|
335
|
+
mostVisibleIdx,
|
|
336
|
+
programmaticScrollRef.current ? "programmatic" : "user"
|
|
337
|
+
);
|
|
338
|
+
}
|
|
479
339
|
},
|
|
480
340
|
{ root: container, threshold: [0.25, 0.5, 0.75] }
|
|
481
341
|
);
|
|
@@ -483,22 +343,28 @@ function MejiroScrollView({
|
|
|
483
343
|
if (el) observer.observe(el);
|
|
484
344
|
}
|
|
485
345
|
return () => observer.disconnect();
|
|
486
|
-
}, []);
|
|
346
|
+
}, [pageCount]);
|
|
487
347
|
useLayoutEffect(() => {
|
|
488
348
|
if (scrollToPage == null) return;
|
|
349
|
+
if (pageCount === 0) return;
|
|
489
350
|
const el = pageRefs.current[scrollToPage];
|
|
490
351
|
if (!(el && containerRef.current)) return;
|
|
352
|
+
programmaticScrollRef.current = true;
|
|
491
353
|
containerRef.current.scrollTo({
|
|
492
354
|
top: el.offsetTop,
|
|
493
355
|
behavior: "auto"
|
|
494
356
|
});
|
|
495
|
-
|
|
496
|
-
|
|
357
|
+
const timer = setTimeout(() => {
|
|
358
|
+
programmaticScrollRef.current = false;
|
|
359
|
+
}, 0);
|
|
360
|
+
return () => clearTimeout(timer);
|
|
361
|
+
}, [scrollToPage, pageCount]);
|
|
362
|
+
return /* @__PURE__ */ jsx7("div", { ref: containerRef, className: "mejiro-reader-scroll", children: /* @__PURE__ */ jsx7(
|
|
497
363
|
"div",
|
|
498
364
|
{
|
|
499
365
|
className: "mejiro-reader-scroll-track",
|
|
500
366
|
style: { display: "flex", flexDirection: "column", gap: pageGap },
|
|
501
|
-
children: pages.map((result, i) => /* @__PURE__ */
|
|
367
|
+
children: pages.map((result, i) => /* @__PURE__ */ jsxs4(
|
|
502
368
|
"div",
|
|
503
369
|
{
|
|
504
370
|
ref: (el) => {
|
|
@@ -508,12 +374,12 @@ function MejiroScrollView({
|
|
|
508
374
|
className: "mejiro-reader-page",
|
|
509
375
|
style: { width: pageWidth, height: pageHeight, flexShrink: 0 },
|
|
510
376
|
children: [
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
513
|
-
/* @__PURE__ */
|
|
514
|
-
/* @__PURE__ */
|
|
377
|
+
/* @__PURE__ */ jsx7("div", { className: "mejiro-reader-page-rule" }),
|
|
378
|
+
/* @__PURE__ */ jsxs4("div", { className: "mejiro-reader-page-header", children: [
|
|
379
|
+
/* @__PURE__ */ jsx7("span", { className: "mejiro-reader-page-header-title" }),
|
|
380
|
+
/* @__PURE__ */ jsx7("span", { className: "mejiro-reader-page-header-num", children: i + 1 })
|
|
515
381
|
] }),
|
|
516
|
-
/* @__PURE__ */
|
|
382
|
+
/* @__PURE__ */ jsx7("div", { className: "mejiro-reader-page-viewport", children: /* @__PURE__ */ jsx7("div", { className: "mejiro-reader-page-clip", style: { height: contentHeight }, children: /* @__PURE__ */ jsx7(
|
|
517
383
|
MejiroPageView,
|
|
518
384
|
{
|
|
519
385
|
result,
|
|
@@ -534,7 +400,7 @@ function MejiroScrollView({
|
|
|
534
400
|
|
|
535
401
|
// src/MejiroSettingsPanel.tsx
|
|
536
402
|
import { normalizeFontFamily as normalizeFontFamily3 } from "@libraz/mejiro/browser";
|
|
537
|
-
import { jsx as
|
|
403
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
538
404
|
var DEFAULT_FONTS = [
|
|
539
405
|
{ value: "serif", label: "System Serif" },
|
|
540
406
|
{ value: "sans-serif", label: "System Sans" }
|
|
@@ -543,6 +409,14 @@ function fontLabelFromCss(css) {
|
|
|
543
409
|
const first = css.split(",")[0]?.trim() ?? css;
|
|
544
410
|
return first.replace(/^["']|["']$/g, "") || css;
|
|
545
411
|
}
|
|
412
|
+
function clampNumber(value, min, max, fallback) {
|
|
413
|
+
if (!Number.isFinite(value)) return fallback;
|
|
414
|
+
return Math.max(min, Math.min(max, value));
|
|
415
|
+
}
|
|
416
|
+
function parseClampedInput(value, min, max, fallback) {
|
|
417
|
+
if (value.trim() === "") return fallback;
|
|
418
|
+
return clampNumber(Number(value), min, max, fallback);
|
|
419
|
+
}
|
|
546
420
|
function MejiroSettingsPanel({
|
|
547
421
|
open,
|
|
548
422
|
settings,
|
|
@@ -555,13 +429,13 @@ function MejiroSettingsPanel({
|
|
|
555
429
|
const patch = (next) => onChange({ ...settings, ...next });
|
|
556
430
|
const currentFont = normalizeFontFamily3(settings.fontFamily);
|
|
557
431
|
const fontOptions = fonts.some((f) => f.value === currentFont) ? fonts : [{ value: currentFont, label: fontLabelFromCss(currentFont) }, ...fonts];
|
|
558
|
-
return /* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
560
|
-
/* @__PURE__ */
|
|
561
|
-
/* @__PURE__ */
|
|
562
|
-
/* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
564
|
-
/* @__PURE__ */
|
|
432
|
+
return /* @__PURE__ */ jsx8("div", { className: `mejiro-reader-settings-panel${open ? " is-open" : ""}`, children: /* @__PURE__ */ jsx8("div", { className: "mejiro-reader-settings-inner", children: /* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-settings-content", children: [
|
|
433
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-settings-group", children: [
|
|
434
|
+
/* @__PURE__ */ jsx8("span", { className: "mejiro-reader-settings-group-title", children: messages.settingsFont }),
|
|
435
|
+
/* @__PURE__ */ jsx8("div", { className: "mejiro-reader-control", children: /* @__PURE__ */ jsx8("select", { value: currentFont, onChange: (e) => patch({ fontFamily: e.target.value }), children: fontOptions.map((f) => /* @__PURE__ */ jsx8("option", { value: f.value, children: f.label }, f.value)) }) }),
|
|
436
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-control", children: [
|
|
437
|
+
/* @__PURE__ */ jsx8("label", { className: "mejiro-reader-control-label", htmlFor: "mejiro-reader-font-size", children: messages.settingsSize }),
|
|
438
|
+
/* @__PURE__ */ jsx8(
|
|
565
439
|
"button",
|
|
566
440
|
{
|
|
567
441
|
type: "button",
|
|
@@ -571,7 +445,7 @@ function MejiroSettingsPanel({
|
|
|
571
445
|
children: "A\u2212"
|
|
572
446
|
}
|
|
573
447
|
),
|
|
574
|
-
/* @__PURE__ */
|
|
448
|
+
/* @__PURE__ */ jsx8(
|
|
575
449
|
"input",
|
|
576
450
|
{
|
|
577
451
|
id: "mejiro-reader-font-size",
|
|
@@ -579,10 +453,17 @@ function MejiroSettingsPanel({
|
|
|
579
453
|
value: settings.fontSize,
|
|
580
454
|
min: minFontSize,
|
|
581
455
|
max: maxFontSize,
|
|
582
|
-
onChange: (e) => patch({
|
|
456
|
+
onChange: (e) => patch({
|
|
457
|
+
fontSize: parseClampedInput(
|
|
458
|
+
e.target.value,
|
|
459
|
+
minFontSize,
|
|
460
|
+
maxFontSize,
|
|
461
|
+
settings.fontSize
|
|
462
|
+
)
|
|
463
|
+
})
|
|
583
464
|
}
|
|
584
465
|
),
|
|
585
|
-
/* @__PURE__ */
|
|
466
|
+
/* @__PURE__ */ jsx8(
|
|
586
467
|
"button",
|
|
587
468
|
{
|
|
588
469
|
type: "button",
|
|
@@ -594,41 +475,41 @@ function MejiroSettingsPanel({
|
|
|
594
475
|
)
|
|
595
476
|
] })
|
|
596
477
|
] }),
|
|
597
|
-
/* @__PURE__ */
|
|
598
|
-
/* @__PURE__ */
|
|
599
|
-
/* @__PURE__ */
|
|
600
|
-
/* @__PURE__ */
|
|
601
|
-
/* @__PURE__ */
|
|
478
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-settings-group", children: [
|
|
479
|
+
/* @__PURE__ */ jsx8("span", { className: "mejiro-reader-settings-group-title", children: messages.settingsLayout }),
|
|
480
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-control", children: [
|
|
481
|
+
/* @__PURE__ */ jsx8("label", { className: "mejiro-reader-control-label", htmlFor: "mejiro-reader-kinsoku", children: messages.settingsKinsoku }),
|
|
482
|
+
/* @__PURE__ */ jsxs5(
|
|
602
483
|
"select",
|
|
603
484
|
{
|
|
604
485
|
id: "mejiro-reader-kinsoku",
|
|
605
486
|
value: settings.mode ?? "strict",
|
|
606
487
|
onChange: (e) => patch({ mode: e.target.value }),
|
|
607
488
|
children: [
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
489
|
+
/* @__PURE__ */ jsx8("option", { value: "strict", children: messages.settingsStrict }),
|
|
490
|
+
/* @__PURE__ */ jsx8("option", { value: "loose", children: messages.settingsLoose })
|
|
610
491
|
]
|
|
611
492
|
}
|
|
612
493
|
)
|
|
613
494
|
] }),
|
|
614
|
-
/* @__PURE__ */
|
|
615
|
-
/* @__PURE__ */
|
|
616
|
-
/* @__PURE__ */
|
|
495
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-control", children: [
|
|
496
|
+
/* @__PURE__ */ jsx8("label", { className: "mejiro-reader-control-label", htmlFor: "mejiro-reader-hanging", children: messages.settingsHanging }),
|
|
497
|
+
/* @__PURE__ */ jsxs5(
|
|
617
498
|
"select",
|
|
618
499
|
{
|
|
619
500
|
id: "mejiro-reader-hanging",
|
|
620
501
|
value: String(settings.enableHanging ?? true),
|
|
621
502
|
onChange: (e) => patch({ enableHanging: e.target.value === "true" }),
|
|
622
503
|
children: [
|
|
623
|
-
/* @__PURE__ */
|
|
624
|
-
/* @__PURE__ */
|
|
504
|
+
/* @__PURE__ */ jsx8("option", { value: "true", children: messages.toggleOn }),
|
|
505
|
+
/* @__PURE__ */ jsx8("option", { value: "false", children: messages.toggleOff })
|
|
625
506
|
]
|
|
626
507
|
}
|
|
627
508
|
)
|
|
628
509
|
] }),
|
|
629
|
-
/* @__PURE__ */
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
510
|
+
/* @__PURE__ */ jsxs5("div", { className: "mejiro-reader-control", children: [
|
|
511
|
+
/* @__PURE__ */ jsx8("label", { className: "mejiro-reader-control-label", htmlFor: "mejiro-reader-line-spacing", children: messages.settingsLineSpacing }),
|
|
512
|
+
/* @__PURE__ */ jsx8(
|
|
632
513
|
"input",
|
|
633
514
|
{
|
|
634
515
|
id: "mejiro-reader-line-spacing",
|
|
@@ -638,7 +519,14 @@ function MejiroSettingsPanel({
|
|
|
638
519
|
min: 1,
|
|
639
520
|
max: 3,
|
|
640
521
|
step: 0.1,
|
|
641
|
-
onChange: (e) => patch({
|
|
522
|
+
onChange: (e) => patch({
|
|
523
|
+
lineSpacing: parseClampedInput(
|
|
524
|
+
e.target.value,
|
|
525
|
+
1,
|
|
526
|
+
3,
|
|
527
|
+
settings.lineSpacing ?? 1.8
|
|
528
|
+
)
|
|
529
|
+
})
|
|
642
530
|
}
|
|
643
531
|
)
|
|
644
532
|
] })
|
|
@@ -653,7 +541,7 @@ import {
|
|
|
653
541
|
} from "react";
|
|
654
542
|
|
|
655
543
|
// src/MejiroImageOverlay.tsx
|
|
656
|
-
import { jsx as
|
|
544
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
657
545
|
function MejiroImageOverlay({
|
|
658
546
|
rect,
|
|
659
547
|
label,
|
|
@@ -663,7 +551,7 @@ function MejiroImageOverlay({
|
|
|
663
551
|
}) {
|
|
664
552
|
const messages = useI18n();
|
|
665
553
|
const resolvedLabel = label ?? messages.imageButton;
|
|
666
|
-
return /* @__PURE__ */
|
|
554
|
+
return /* @__PURE__ */ jsxs6(
|
|
667
555
|
"div",
|
|
668
556
|
{
|
|
669
557
|
className: "mejiro-reader-image-overlay",
|
|
@@ -675,12 +563,12 @@ function MejiroImageOverlay({
|
|
|
675
563
|
},
|
|
676
564
|
onPointerDown: onOverlayPointerDown,
|
|
677
565
|
children: [
|
|
678
|
-
/* @__PURE__ */
|
|
679
|
-
/* @__PURE__ */
|
|
680
|
-
/* @__PURE__ */
|
|
566
|
+
/* @__PURE__ */ jsxs6("div", { className: "mejiro-reader-image-overlay-label", children: [
|
|
567
|
+
/* @__PURE__ */ jsx9("div", { className: "mejiro-reader-image-overlay-icon" }),
|
|
568
|
+
/* @__PURE__ */ jsx9("span", { children: resolvedLabel })
|
|
681
569
|
] }),
|
|
682
|
-
/* @__PURE__ */
|
|
683
|
-
/* @__PURE__ */
|
|
570
|
+
/* @__PURE__ */ jsx9("div", { className: "mejiro-reader-image-overlay-resize", onPointerDown: onResizePointerDown }),
|
|
571
|
+
/* @__PURE__ */ jsx9(
|
|
684
572
|
"button",
|
|
685
573
|
{
|
|
686
574
|
type: "button",
|
|
@@ -706,7 +594,7 @@ function MejiroImageOverlay({
|
|
|
706
594
|
}
|
|
707
595
|
|
|
708
596
|
// src/MejiroSelectionLayer.tsx
|
|
709
|
-
import { jsx as
|
|
597
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
710
598
|
function MejiroSelectionLayer({
|
|
711
599
|
rects,
|
|
712
600
|
side,
|
|
@@ -717,7 +605,7 @@ function MejiroSelectionLayer({
|
|
|
717
605
|
}) {
|
|
718
606
|
const wrapperClass = className ? `mejiro-selection-layer ${className}` : "mejiro-selection-layer";
|
|
719
607
|
const rectClass = rectClassName ?? "mejiro-selection-rect";
|
|
720
|
-
return /* @__PURE__ */
|
|
608
|
+
return /* @__PURE__ */ jsx10(
|
|
721
609
|
"div",
|
|
722
610
|
{
|
|
723
611
|
className: wrapperClass,
|
|
@@ -730,7 +618,7 @@ function MejiroSelectionLayer({
|
|
|
730
618
|
children: rects.map((r, i) => {
|
|
731
619
|
if (r.side !== side) return null;
|
|
732
620
|
const posStyle = side === "right" ? { left: r.x, top: r.y } : { right: -(r.x + r.width), top: r.y };
|
|
733
|
-
return /* @__PURE__ */
|
|
621
|
+
return /* @__PURE__ */ jsx10(
|
|
734
622
|
"div",
|
|
735
623
|
{
|
|
736
624
|
className: rectClass,
|
|
@@ -750,11 +638,11 @@ function MejiroSelectionLayer({
|
|
|
750
638
|
}
|
|
751
639
|
|
|
752
640
|
// src/MejiroSpread.tsx
|
|
753
|
-
import { jsx as
|
|
641
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
754
642
|
function defaultHeader(data) {
|
|
755
|
-
return /* @__PURE__ */
|
|
756
|
-
/* @__PURE__ */
|
|
757
|
-
/* @__PURE__ */
|
|
643
|
+
return /* @__PURE__ */ jsxs7("div", { className: "mejiro-reader-page-header", children: [
|
|
644
|
+
/* @__PURE__ */ jsx11("span", { className: "mejiro-reader-page-header-title", children: data.title ?? "" }),
|
|
645
|
+
/* @__PURE__ */ jsx11("span", { className: "mejiro-reader-page-header-num", children: data.pageNumber != null ? String(data.pageNumber) : "" })
|
|
758
646
|
] });
|
|
759
647
|
}
|
|
760
648
|
function MejiroSpread({
|
|
@@ -869,16 +757,16 @@ function MejiroSpread({
|
|
|
869
757
|
height: pageHeight
|
|
870
758
|
};
|
|
871
759
|
if (isRight && hasImages) pageStyle.overflow = "visible";
|
|
872
|
-
return /* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ jsxs7(
|
|
873
761
|
"div",
|
|
874
762
|
{
|
|
875
763
|
className: `mejiro-reader-page mejiro-reader-page--${side}`,
|
|
876
764
|
style: pageStyle,
|
|
877
765
|
children: [
|
|
878
|
-
/* @__PURE__ */
|
|
766
|
+
/* @__PURE__ */ jsx11("div", { className: "mejiro-reader-page-rule" }),
|
|
879
767
|
renderPageHeader ? renderPageHeader(side, header) : defaultHeader(header),
|
|
880
|
-
/* @__PURE__ */
|
|
881
|
-
/* @__PURE__ */
|
|
768
|
+
/* @__PURE__ */ jsx11("div", { className: "mejiro-reader-page-viewport", children: /* @__PURE__ */ jsxs7("div", { className: "mejiro-reader-page-clip", style: { height: contentHeight }, children: [
|
|
769
|
+
/* @__PURE__ */ jsx11(
|
|
882
770
|
MejiroPageView,
|
|
883
771
|
{
|
|
884
772
|
result,
|
|
@@ -890,9 +778,9 @@ function MejiroSpread({
|
|
|
890
778
|
},
|
|
891
779
|
pageKey
|
|
892
780
|
),
|
|
893
|
-
selectionRects && selectionRects.length > 0 && /* @__PURE__ */
|
|
781
|
+
selectionRects && selectionRects.length > 0 && /* @__PURE__ */ jsx11(MejiroSelectionLayer, { rects: selectionRects, side })
|
|
894
782
|
] }) }),
|
|
895
|
-
isRight && images.map((item) => /* @__PURE__ */
|
|
783
|
+
isRight && images.map((item) => /* @__PURE__ */ jsx11(
|
|
896
784
|
MejiroImageOverlay,
|
|
897
785
|
{
|
|
898
786
|
rect: item.rect,
|
|
@@ -919,7 +807,7 @@ function MejiroSpread({
|
|
|
919
807
|
if (selectionEnabled) handlePointerUp(e);
|
|
920
808
|
}
|
|
921
809
|
const useCombined = selectionEnabled || gestureEnabled;
|
|
922
|
-
return /* @__PURE__ */
|
|
810
|
+
return /* @__PURE__ */ jsx11("div", { className: "mejiro-reader-book", children: /* @__PURE__ */ jsxs7(
|
|
923
811
|
"div",
|
|
924
812
|
{
|
|
925
813
|
className: `mejiro-reader-spread${turning ? " is-turning" : ""}${singlePage ? " mejiro-reader-spread--single" : ""}`,
|
|
@@ -930,7 +818,7 @@ function MejiroSpread({
|
|
|
930
818
|
children: [
|
|
931
819
|
renderPage("right"),
|
|
932
820
|
!singlePage && renderPage("left"),
|
|
933
|
-
/* @__PURE__ */
|
|
821
|
+
/* @__PURE__ */ jsx11(
|
|
934
822
|
"button",
|
|
935
823
|
{
|
|
936
824
|
type: "button",
|
|
@@ -939,7 +827,7 @@ function MejiroSpread({
|
|
|
939
827
|
onClick: onPrev
|
|
940
828
|
}
|
|
941
829
|
),
|
|
942
|
-
/* @__PURE__ */
|
|
830
|
+
/* @__PURE__ */ jsx11(
|
|
943
831
|
"button",
|
|
944
832
|
{
|
|
945
833
|
type: "button",
|
|
@@ -956,7 +844,7 @@ function MejiroSpread({
|
|
|
956
844
|
|
|
957
845
|
// src/MejiroStats.tsx
|
|
958
846
|
import { estimateReadingTime, formatReadingTime } from "@libraz/mejiro/book";
|
|
959
|
-
import { jsx as
|
|
847
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
960
848
|
function MejiroStats({
|
|
961
849
|
chapter,
|
|
962
850
|
totalPages,
|
|
@@ -966,7 +854,7 @@ function MejiroStats({
|
|
|
966
854
|
cpm = 600,
|
|
967
855
|
readingTimeLocale = "ja"
|
|
968
856
|
}) {
|
|
969
|
-
if (!chapter) return /* @__PURE__ */
|
|
857
|
+
if (!chapter) return /* @__PURE__ */ jsx12("span", { className: "mejiro-reader-stats" });
|
|
970
858
|
const totalChars = chapter.paragraphs.reduce((s, p) => s + p.text.length, 0);
|
|
971
859
|
const totalRuby = chapter.paragraphs.reduce(
|
|
972
860
|
(s, p) => s + p.inlineAnnotations.filter((a) => a.kind === "ruby").length,
|
|
@@ -981,7 +869,7 @@ function MejiroStats({
|
|
|
981
869
|
fontLabel || null,
|
|
982
870
|
`${elapsedMs.toFixed(0)}ms`
|
|
983
871
|
];
|
|
984
|
-
return /* @__PURE__ */
|
|
872
|
+
return /* @__PURE__ */ jsx12("span", { className: "mejiro-reader-stats", children: parts.filter(Boolean).join(" / ") });
|
|
985
873
|
}
|
|
986
874
|
|
|
987
875
|
// src/useChapterLayout.ts
|
|
@@ -1458,6 +1346,7 @@ function useSpread(layout, options = {}) {
|
|
|
1458
1346
|
spreadIdxRef.current = spreadIdx;
|
|
1459
1347
|
const turnTimerRef = useRef8(null);
|
|
1460
1348
|
const layoutGenerationRef = useRef8(0);
|
|
1349
|
+
const lastEmittedRef = useRef8(null);
|
|
1461
1350
|
const totalPages = layout?.totalPages ?? 0;
|
|
1462
1351
|
const totalSpreads = Math.max(1, Math.ceil(totalPages / 2));
|
|
1463
1352
|
const refresh = useCallback5(() => {
|
|
@@ -1484,7 +1373,15 @@ function useSpread(layout, options = {}) {
|
|
|
1484
1373
|
useEffect5(() => {
|
|
1485
1374
|
if (!layout) return;
|
|
1486
1375
|
setSpread(layout.getSpread(spreadIdx));
|
|
1487
|
-
|
|
1376
|
+
const last = lastEmittedRef.current;
|
|
1377
|
+
if (!last) {
|
|
1378
|
+
lastEmittedRef.current = { layout, spreadIdx };
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
if (last.spreadIdx !== spreadIdx) {
|
|
1382
|
+
onChangeRef.current?.(spreadIdx);
|
|
1383
|
+
}
|
|
1384
|
+
lastEmittedRef.current = { layout, spreadIdx };
|
|
1488
1385
|
}, [layout, spreadIdx]);
|
|
1489
1386
|
const goTo = useCallback5(
|
|
1490
1387
|
(index) => {
|
|
@@ -1551,12 +1448,12 @@ function useSpread(layout, options = {}) {
|
|
|
1551
1448
|
}
|
|
1552
1449
|
|
|
1553
1450
|
// src/MejiroReader.tsx
|
|
1554
|
-
import { jsx as
|
|
1451
|
+
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1555
1452
|
function MejiroReaderInner(props, ref) {
|
|
1556
1453
|
const manuscriptProp = "manuscript" in props ? props.manuscript : void 0;
|
|
1557
1454
|
const dialectProp = "dialect" in props ? props.dialect : void 0;
|
|
1558
1455
|
const {
|
|
1559
|
-
options
|
|
1456
|
+
options: optionsProp,
|
|
1560
1457
|
pageGeometry: pageGeometryProp,
|
|
1561
1458
|
fonts,
|
|
1562
1459
|
epub: epubProp,
|
|
@@ -1601,6 +1498,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
1601
1498
|
const fileRef = useRef9(null);
|
|
1602
1499
|
const [settingsOpen, setSettingsOpen] = useState7(false);
|
|
1603
1500
|
const [chapterState, setChapterState] = useState7(chapterProp ?? 0);
|
|
1501
|
+
const chapterIsUncontrolled = chapterProp == null;
|
|
1604
1502
|
const chapter = chapterProp ?? chapterState;
|
|
1605
1503
|
const [chromeHidden, setChromeHidden] = useState7(false);
|
|
1606
1504
|
const [autoSingle, setAutoSingle] = useState7(false);
|
|
@@ -1645,7 +1543,19 @@ function MejiroReaderInner(props, ref) {
|
|
|
1645
1543
|
const aspect = resolvedGeometry?.aspect ?? DEFAULT_PAGE_GEOMETRY.aspect;
|
|
1646
1544
|
return `${columns} / ${aspect}`;
|
|
1647
1545
|
}, [effectiveSingle, resolvedGeometry]);
|
|
1648
|
-
const
|
|
1546
|
+
const resolvedOptions = useMemo4(
|
|
1547
|
+
() => ({ ...DEFAULT_BOOK_OPTIONS, ...optionsProp ?? {} }),
|
|
1548
|
+
[optionsProp]
|
|
1549
|
+
);
|
|
1550
|
+
const { book, options: bookOptions, setOptions } = useMejiroBook(resolvedOptions);
|
|
1551
|
+
const didSyncOptionsPropRef = useRef9(false);
|
|
1552
|
+
useEffect6(() => {
|
|
1553
|
+
if (!didSyncOptionsPropRef.current) {
|
|
1554
|
+
didSyncOptionsPropRef.current = true;
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
void setOptions(resolvedOptions);
|
|
1558
|
+
}, [resolvedOptions, setOptions]);
|
|
1649
1559
|
const synthesizedEpub = useMemo4(() => {
|
|
1650
1560
|
if (manuscriptProp === void 0) return null;
|
|
1651
1561
|
return manuscriptToEpubBook(manuscriptProp, { dialect: dialectProp });
|
|
@@ -1752,11 +1662,11 @@ function MejiroReaderInner(props, ref) {
|
|
|
1752
1662
|
onLoadRef.current = onLoad;
|
|
1753
1663
|
useEffect6(() => {
|
|
1754
1664
|
if (!controlled) return;
|
|
1755
|
-
if (
|
|
1665
|
+
if (chapterIsUncontrolled) setChapterState(0);
|
|
1756
1666
|
clearImagesRef.current();
|
|
1757
1667
|
book.clearCache();
|
|
1758
|
-
if (
|
|
1759
|
-
}, [controlled,
|
|
1668
|
+
if (e) onLoadRef.current?.(e);
|
|
1669
|
+
}, [controlled, e, book, chapterIsUncontrolled]);
|
|
1760
1670
|
const spreadGoToRef = useRef9(spreadCtx.goTo);
|
|
1761
1671
|
spreadGoToRef.current = spreadCtx.goTo;
|
|
1762
1672
|
useEffect6(() => {
|
|
@@ -1950,17 +1860,17 @@ function MejiroReaderInner(props, ref) {
|
|
|
1950
1860
|
}, [themeOverride, pageGeometryProp, fit, surfaceAspect]);
|
|
1951
1861
|
const resolvedMessages = useI18n({ locale, messages });
|
|
1952
1862
|
const effectiveSubtitle = subtitle ?? resolvedMessages.logoSubtitle;
|
|
1953
|
-
const defaultLogo = /* @__PURE__ */
|
|
1954
|
-
/* @__PURE__ */
|
|
1955
|
-
effectiveSubtitle && /* @__PURE__ */
|
|
1863
|
+
const defaultLogo = /* @__PURE__ */ jsxs8("div", { className: "mejiro-reader-logo", children: [
|
|
1864
|
+
/* @__PURE__ */ jsx13("span", { className: "mejiro-reader-logo-mark", children: title }),
|
|
1865
|
+
effectiveSubtitle && /* @__PURE__ */ jsx13("span", { className: "mejiro-reader-logo-sub", children: effectiveSubtitle })
|
|
1956
1866
|
] });
|
|
1957
|
-
const header = enableHeader ? /* @__PURE__ */
|
|
1958
|
-
/* @__PURE__ */
|
|
1867
|
+
const header = enableHeader ? /* @__PURE__ */ jsxs8("header", { className: "mejiro-reader-header", children: [
|
|
1868
|
+
/* @__PURE__ */ jsxs8("div", { className: "mejiro-reader-header-left", children: [
|
|
1959
1869
|
logo === void 0 ? defaultLogo : logo,
|
|
1960
|
-
showChapterSelect && /* @__PURE__ */
|
|
1870
|
+
showChapterSelect && /* @__PURE__ */ jsx13(MejiroChapterNav, { epub: e, chapter, onChange: onChapter })
|
|
1961
1871
|
] }),
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
enableStats && /* @__PURE__ */
|
|
1872
|
+
/* @__PURE__ */ jsxs8("div", { className: "mejiro-reader-header-actions", children: [
|
|
1873
|
+
enableStats && /* @__PURE__ */ jsx13(
|
|
1964
1874
|
MejiroStats,
|
|
1965
1875
|
{
|
|
1966
1876
|
chapter: e?.chapters[chapter] ?? null,
|
|
@@ -1969,7 +1879,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
1969
1879
|
fontLabel
|
|
1970
1880
|
}
|
|
1971
1881
|
),
|
|
1972
|
-
enableDropZone && /* @__PURE__ */
|
|
1882
|
+
enableDropZone && /* @__PURE__ */ jsx13(
|
|
1973
1883
|
"button",
|
|
1974
1884
|
{
|
|
1975
1885
|
type: "button",
|
|
@@ -1978,7 +1888,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
1978
1888
|
children: resolvedMessages.openButton
|
|
1979
1889
|
}
|
|
1980
1890
|
),
|
|
1981
|
-
enableImageOverlay && e && /* @__PURE__ */
|
|
1891
|
+
enableImageOverlay && e && /* @__PURE__ */ jsx13(
|
|
1982
1892
|
"button",
|
|
1983
1893
|
{
|
|
1984
1894
|
type: "button",
|
|
@@ -1987,7 +1897,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
1987
1897
|
children: resolvedMessages.imageButton
|
|
1988
1898
|
}
|
|
1989
1899
|
),
|
|
1990
|
-
enableSettings && /* @__PURE__ */
|
|
1900
|
+
enableSettings && /* @__PURE__ */ jsxs8(
|
|
1991
1901
|
"button",
|
|
1992
1902
|
{
|
|
1993
1903
|
type: "button",
|
|
@@ -1995,7 +1905,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
1995
1905
|
onClick: () => setSettingsOpen((v) => !v),
|
|
1996
1906
|
children: [
|
|
1997
1907
|
resolvedMessages.settingsButton,
|
|
1998
|
-
/* @__PURE__ */
|
|
1908
|
+
/* @__PURE__ */ jsx13("span", { className: "mejiro-reader-btn-arrow", children: "\u25BE" })
|
|
1999
1909
|
]
|
|
2000
1910
|
}
|
|
2001
1911
|
)
|
|
@@ -2007,7 +1917,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
2007
1917
|
const showLeft = spreadCtx.spread != null && leftPage <= spreadCtx.spread.totalPages;
|
|
2008
1918
|
const showRightNum = pageNumbers === "both" || pageNumbers === "right";
|
|
2009
1919
|
const showLeftNum = pageNumbers === "both" || pageNumbers === "left";
|
|
2010
|
-
return /* @__PURE__ */
|
|
1920
|
+
return /* @__PURE__ */ jsx13(MejiroI18nProvider, { messages: resolvedMessages, children: /* @__PURE__ */ jsxs8(
|
|
2011
1921
|
"div",
|
|
2012
1922
|
{
|
|
2013
1923
|
className: `mejiro-reader${chromeHidden ? " mejiro-reader--chrome-hidden" : ""}${fit === "width" ? " mejiro-reader--fit-width" : ""}`,
|
|
@@ -2015,12 +1925,12 @@ function MejiroReaderInner(props, ref) {
|
|
|
2015
1925
|
style: themeStyle,
|
|
2016
1926
|
children: [
|
|
2017
1927
|
header,
|
|
2018
|
-
enableSettings && (renderSettings ? /* @__PURE__ */
|
|
1928
|
+
enableSettings && (renderSettings ? /* @__PURE__ */ jsx13("div", { className: `mejiro-reader-settings-panel${settingsOpen ? " is-open" : ""}`, children: /* @__PURE__ */ jsx13("div", { className: "mejiro-reader-settings-inner", children: /* @__PURE__ */ jsx13("div", { className: "mejiro-reader-settings-content", children: renderSettings({
|
|
2019
1929
|
settings: editable,
|
|
2020
1930
|
update: setOptions,
|
|
2021
1931
|
open: settingsOpen,
|
|
2022
1932
|
toggle: () => setSettingsOpen((v) => !v)
|
|
2023
|
-
}) }) }) }) : /* @__PURE__ */
|
|
1933
|
+
}) }) }) }) : /* @__PURE__ */ jsx13(
|
|
2024
1934
|
MejiroSettingsPanel,
|
|
2025
1935
|
{
|
|
2026
1936
|
open: settingsOpen,
|
|
@@ -2029,13 +1939,13 @@ function MejiroReaderInner(props, ref) {
|
|
|
2029
1939
|
onChange: setOptions
|
|
2030
1940
|
}
|
|
2031
1941
|
)),
|
|
2032
|
-
/* @__PURE__ */
|
|
2033
|
-
showChapterPanel && /* @__PURE__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2035
|
-
!(e || epubCtx.loading) && enableDropZone && /* @__PURE__ */
|
|
2036
|
-
epubCtx.loading && /* @__PURE__ */
|
|
2037
|
-
!layoutReady && fallback && /* @__PURE__ */
|
|
2038
|
-
layoutReady && mode === "scroll" && layoutCtx.layout && /* @__PURE__ */
|
|
1942
|
+
/* @__PURE__ */ jsxs8("div", { className: `mejiro-reader-body${showChapterPanel ? " has-chapter-panel" : ""}`, children: [
|
|
1943
|
+
showChapterPanel && /* @__PURE__ */ jsx13(MejiroChapterNav, { epub: e, chapter, onChange: onChapter, variant: "panel" }),
|
|
1944
|
+
/* @__PURE__ */ jsxs8("div", { ref: surfaceRef, className: "mejiro-reader-surface", children: [
|
|
1945
|
+
!(e || epubCtx.loading) && enableDropZone && /* @__PURE__ */ jsx13(MejiroDropZone, { onFile: (f) => void epubCtx.loadFile(f) }),
|
|
1946
|
+
epubCtx.loading && /* @__PURE__ */ jsx13("div", { className: "mejiro-reader-loading", children: resolvedMessages.loading }),
|
|
1947
|
+
!layoutReady && fallback && /* @__PURE__ */ jsx13("div", { className: "mejiro-reader-fallback", children: fallback }),
|
|
1948
|
+
layoutReady && mode === "scroll" && layoutCtx.layout && /* @__PURE__ */ jsx13(
|
|
2039
1949
|
MejiroScrollView,
|
|
2040
1950
|
{
|
|
2041
1951
|
layout: layoutCtx.layout,
|
|
@@ -2046,13 +1956,14 @@ function MejiroReaderInner(props, ref) {
|
|
|
2046
1956
|
fontSize: bookOptions.fontSize,
|
|
2047
1957
|
lineSpacing: bookOptions.lineSpacing,
|
|
2048
1958
|
scrollToPage: spreadCtx.spreadIdx * 2,
|
|
2049
|
-
onVisiblePageChange: (pageIdx) => {
|
|
1959
|
+
onVisiblePageChange: (pageIdx, source) => {
|
|
1960
|
+
if (source === "programmatic") return;
|
|
2050
1961
|
const target = Math.floor(pageIdx / 2);
|
|
2051
|
-
if (target !== spreadCtx.spreadIdx)
|
|
1962
|
+
if (target !== spreadCtx.spreadIdx) spreadCtx.setSpread(target);
|
|
2052
1963
|
}
|
|
2053
1964
|
}
|
|
2054
1965
|
),
|
|
2055
|
-
layoutReady && mode === "paginated" && spreadCtx.spread && /* @__PURE__ */
|
|
1966
|
+
layoutReady && mode === "paginated" && spreadCtx.spread && /* @__PURE__ */ jsx13(
|
|
2056
1967
|
MejiroSpread,
|
|
2057
1968
|
{
|
|
2058
1969
|
singlePage: effectiveSingle,
|
|
@@ -2075,7 +1986,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
2075
1986
|
pageNumber: showLeft && showLeftNum ? leftPage : null
|
|
2076
1987
|
},
|
|
2077
1988
|
images: imageCtx.currentImages,
|
|
2078
|
-
indicator: enablePageIndicator ? /* @__PURE__ */
|
|
1989
|
+
indicator: enablePageIndicator ? /* @__PURE__ */ jsx13(
|
|
2079
1990
|
MejiroPageIndicator,
|
|
2080
1991
|
{
|
|
2081
1992
|
current: spreadCtx.spreadIdx + 1,
|
|
@@ -2093,7 +2004,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
2093
2004
|
)
|
|
2094
2005
|
] })
|
|
2095
2006
|
] }),
|
|
2096
|
-
/* @__PURE__ */
|
|
2007
|
+
/* @__PURE__ */ jsx13(
|
|
2097
2008
|
"input",
|
|
2098
2009
|
{
|
|
2099
2010
|
ref: fileRef,
|
|
@@ -2106,7 +2017,7 @@ function MejiroReaderInner(props, ref) {
|
|
|
2106
2017
|
}
|
|
2107
2018
|
}
|
|
2108
2019
|
),
|
|
2109
|
-
/* @__PURE__ */
|
|
2020
|
+
/* @__PURE__ */ jsx13("div", { className: "mejiro-reader-sr-only", role: "status", "aria-live": "polite", children: spreadCtx.totalSpreads > 0 ? format(resolvedMessages.spreadAnnouncement, {
|
|
2110
2021
|
spread: spreadCtx.spreadIdx + 1,
|
|
2111
2022
|
total: spreadCtx.totalSpreads
|
|
2112
2023
|
}) : "" })
|
|
@@ -2118,7 +2029,7 @@ var MejiroReader = forwardRef(MejiroReaderInner);
|
|
|
2118
2029
|
MejiroReader.displayName = "MejiroReader";
|
|
2119
2030
|
|
|
2120
2031
|
// src/MejiroEditor.tsx
|
|
2121
|
-
import { Fragment as
|
|
2032
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2122
2033
|
function cloneBook(book) {
|
|
2123
2034
|
return {
|
|
2124
2035
|
...book,
|
|
@@ -2194,8 +2105,11 @@ function MejiroEditor({
|
|
|
2194
2105
|
const book = editor?.book ?? null;
|
|
2195
2106
|
const chapter = book?.chapters[selection.chapter] ?? null;
|
|
2196
2107
|
const paragraph = chapter?.paragraphs[selection.paragraph] ?? null;
|
|
2197
|
-
const
|
|
2198
|
-
|
|
2108
|
+
const textDirty = paragraph ? text !== paragraph.text : false;
|
|
2109
|
+
const previewBook = useMemo5(() => {
|
|
2110
|
+
void revision;
|
|
2111
|
+
return book ? cloneBook(book) : null;
|
|
2112
|
+
}, [book, revision]);
|
|
2199
2113
|
useEffect7(() => {
|
|
2200
2114
|
onLoadRef.current = onLoad;
|
|
2201
2115
|
}, [onLoad]);
|
|
@@ -2289,7 +2203,7 @@ function MejiroEditor({
|
|
|
2289
2203
|
setRevision((value) => value + 1);
|
|
2290
2204
|
}
|
|
2291
2205
|
function applyRuby() {
|
|
2292
|
-
if (!(editor && paragraph && rubyText.trim())) return;
|
|
2206
|
+
if (!(editor && paragraph && rubyText.trim()) || textDirty) return;
|
|
2293
2207
|
const len = [...text].length;
|
|
2294
2208
|
const start = Math.max(0, Math.min(rubyStart, len));
|
|
2295
2209
|
const end = Math.max(start + 1, Math.min(rubyEnd, len));
|
|
@@ -2340,9 +2254,9 @@ function MejiroEditor({
|
|
|
2340
2254
|
a.click();
|
|
2341
2255
|
URL.revokeObjectURL(url);
|
|
2342
2256
|
}
|
|
2343
|
-
return /* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2345
|
-
previewBook ? /* @__PURE__ */
|
|
2257
|
+
return /* @__PURE__ */ jsxs9("div", { className: "mejiro-editor", children: [
|
|
2258
|
+
/* @__PURE__ */ jsxs9("main", { className: "mejiro-editor-preview", children: [
|
|
2259
|
+
previewBook ? /* @__PURE__ */ jsx14(
|
|
2346
2260
|
MejiroReader,
|
|
2347
2261
|
{
|
|
2348
2262
|
epub: previewBook,
|
|
@@ -2352,38 +2266,38 @@ function MejiroEditor({
|
|
|
2352
2266
|
enableImageOverlay: false,
|
|
2353
2267
|
enableSurfaceTap: false
|
|
2354
2268
|
}
|
|
2355
|
-
) : /* @__PURE__ */
|
|
2356
|
-
loading && /* @__PURE__ */
|
|
2357
|
-
error && /* @__PURE__ */
|
|
2269
|
+
) : /* @__PURE__ */ jsx14(MejiroDropZone, { onFile: (file) => void loadFile(file) }),
|
|
2270
|
+
loading && /* @__PURE__ */ jsx14("div", { className: "mejiro-editor-loading", children: messages.loading }),
|
|
2271
|
+
error && /* @__PURE__ */ jsx14("div", { className: "mejiro-editor-error", children: error.message })
|
|
2358
2272
|
] }),
|
|
2359
|
-
/* @__PURE__ */
|
|
2360
|
-
/* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2362
|
-
/* @__PURE__ */
|
|
2363
|
-
editor?.author && /* @__PURE__ */
|
|
2273
|
+
/* @__PURE__ */ jsxs9("aside", { className: "mejiro-editor-panel", children: [
|
|
2274
|
+
/* @__PURE__ */ jsxs9("div", { className: "mejiro-editor-head", children: [
|
|
2275
|
+
/* @__PURE__ */ jsx14("span", { children: messages.editorTitle }),
|
|
2276
|
+
/* @__PURE__ */ jsx14("strong", { children: editor?.title ?? messages.editorNoBookLoaded }),
|
|
2277
|
+
editor?.author && /* @__PURE__ */ jsx14("small", { children: editor.author })
|
|
2364
2278
|
] }),
|
|
2365
|
-
book && /* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2367
|
-
/* @__PURE__ */
|
|
2368
|
-
/* @__PURE__ */
|
|
2369
|
-
(ch, ci) => ch.blocks.filter((b) => b.kind === "paragraph").map((block, pi) => /* @__PURE__ */
|
|
2279
|
+
book && /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
2280
|
+
/* @__PURE__ */ jsxs9("div", { className: "mejiro-editor-section", children: [
|
|
2281
|
+
/* @__PURE__ */ jsx14("span", { className: "mejiro-editor-label", children: messages.editorParagraphs }),
|
|
2282
|
+
/* @__PURE__ */ jsx14("div", { className: "mejiro-editor-paragraphs", children: book.chapters.map(
|
|
2283
|
+
(ch, ci) => ch.blocks.filter((b) => b.kind === "paragraph").map((block, pi) => /* @__PURE__ */ jsxs9(
|
|
2370
2284
|
"button",
|
|
2371
2285
|
{
|
|
2372
2286
|
type: "button",
|
|
2373
2287
|
className: selection.chapter === ci && selection.paragraph === pi ? "is-active" : "",
|
|
2374
2288
|
onClick: () => selectParagraph(ci, pi),
|
|
2375
2289
|
children: [
|
|
2376
|
-
/* @__PURE__ */
|
|
2377
|
-
/* @__PURE__ */
|
|
2290
|
+
/* @__PURE__ */ jsx14("span", { children: ch.title ?? format(messages.chapterN, { n: ci + 1 }) }),
|
|
2291
|
+
/* @__PURE__ */ jsx14("strong", { children: block.text.slice(0, 42) })
|
|
2378
2292
|
]
|
|
2379
2293
|
},
|
|
2380
2294
|
`${ch.href}-${block.id}`
|
|
2381
2295
|
))
|
|
2382
2296
|
) })
|
|
2383
2297
|
] }),
|
|
2384
|
-
enableProofread && /* @__PURE__ */
|
|
2385
|
-
/* @__PURE__ */
|
|
2386
|
-
/* @__PURE__ */
|
|
2298
|
+
enableProofread && /* @__PURE__ */ jsxs9("div", { className: "mejiro-editor-section", children: [
|
|
2299
|
+
/* @__PURE__ */ jsx14("span", { className: "mejiro-editor-label", children: messages.editorProofread }),
|
|
2300
|
+
/* @__PURE__ */ jsx14(
|
|
2387
2301
|
"textarea",
|
|
2388
2302
|
{
|
|
2389
2303
|
ref: textareaRef,
|
|
@@ -2392,17 +2306,17 @@ function MejiroEditor({
|
|
|
2392
2306
|
onSelect: captureRubyRange
|
|
2393
2307
|
}
|
|
2394
2308
|
),
|
|
2395
|
-
/* @__PURE__ */
|
|
2309
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "mejiro-editor-primary", onClick: applyText, children: messages.editorApplyText })
|
|
2396
2310
|
] }),
|
|
2397
|
-
enableRuby && /* @__PURE__ */
|
|
2398
|
-
/* @__PURE__ */
|
|
2399
|
-
/* @__PURE__ */
|
|
2400
|
-
/* @__PURE__ */
|
|
2311
|
+
enableRuby && /* @__PURE__ */ jsxs9("div", { className: "mejiro-editor-section", children: [
|
|
2312
|
+
/* @__PURE__ */ jsx14("span", { className: "mejiro-editor-label", children: messages.editorRuby }),
|
|
2313
|
+
/* @__PURE__ */ jsx14("p", { className: "mejiro-editor-hint", children: messages.editorRubyHint }),
|
|
2314
|
+
/* @__PURE__ */ jsx14("p", { className: "mejiro-editor-range", children: format(messages.editorRubyRange, {
|
|
2401
2315
|
start: rubyStart,
|
|
2402
2316
|
end: rubyEnd,
|
|
2403
2317
|
count: Math.max(0, rubyEnd - rubyStart)
|
|
2404
2318
|
}) }),
|
|
2405
|
-
/* @__PURE__ */
|
|
2319
|
+
/* @__PURE__ */ jsx14(
|
|
2406
2320
|
"input",
|
|
2407
2321
|
{
|
|
2408
2322
|
value: rubyText,
|
|
@@ -2410,12 +2324,21 @@ function MejiroEditor({
|
|
|
2410
2324
|
onChange: (event) => setRubyText(event.target.value)
|
|
2411
2325
|
}
|
|
2412
2326
|
),
|
|
2413
|
-
/* @__PURE__ */
|
|
2327
|
+
/* @__PURE__ */ jsx14(
|
|
2328
|
+
"button",
|
|
2329
|
+
{
|
|
2330
|
+
type: "button",
|
|
2331
|
+
className: "mejiro-editor-primary",
|
|
2332
|
+
disabled: textDirty || !rubyText.trim(),
|
|
2333
|
+
onClick: applyRuby,
|
|
2334
|
+
children: messages.editorApplyRuby
|
|
2335
|
+
}
|
|
2336
|
+
)
|
|
2414
2337
|
] }),
|
|
2415
|
-
enableImages && /* @__PURE__ */
|
|
2416
|
-
/* @__PURE__ */
|
|
2417
|
-
/* @__PURE__ */
|
|
2418
|
-
/* @__PURE__ */
|
|
2338
|
+
enableImages && /* @__PURE__ */ jsxs9("div", { className: "mejiro-editor-section", children: [
|
|
2339
|
+
/* @__PURE__ */ jsx14("span", { className: "mejiro-editor-label", children: messages.editorImages }),
|
|
2340
|
+
/* @__PURE__ */ jsx14("button", { type: "button", onClick: () => imageInputRef.current?.click(), children: messages.editorInsertImageAfterParagraph }),
|
|
2341
|
+
/* @__PURE__ */ jsx14(
|
|
2419
2342
|
"input",
|
|
2420
2343
|
{
|
|
2421
2344
|
ref: imageInputRef,
|
|
@@ -2429,7 +2352,7 @@ function MejiroEditor({
|
|
|
2429
2352
|
}
|
|
2430
2353
|
)
|
|
2431
2354
|
] }),
|
|
2432
|
-
enableExport && /* @__PURE__ */
|
|
2355
|
+
enableExport && /* @__PURE__ */ jsx14(
|
|
2433
2356
|
"button",
|
|
2434
2357
|
{
|
|
2435
2358
|
type: "button",
|
|
@@ -2454,35 +2377,189 @@ function paragraphBlockId(chapter, paragraphIndex) {
|
|
|
2454
2377
|
|
|
2455
2378
|
// src/MejiroManuscriptEditor.tsx
|
|
2456
2379
|
import { EpubProject } from "@libraz/mejiro/epub";
|
|
2457
|
-
import { useCallback as useCallback9, useEffect as useEffect9, useRef as
|
|
2380
|
+
import { useCallback as useCallback9, useEffect as useEffect9, useRef as useRef13, useState as useState11 } from "react";
|
|
2381
|
+
|
|
2382
|
+
// src/MejiroNotationHighlighter.tsx
|
|
2383
|
+
import { tokenizeManuscriptSource } from "@libraz/mejiro";
|
|
2384
|
+
import {
|
|
2385
|
+
forwardRef as forwardRef2,
|
|
2386
|
+
useImperativeHandle as useImperativeHandle2,
|
|
2387
|
+
useMemo as useMemo6,
|
|
2388
|
+
useRef as useRef11,
|
|
2389
|
+
useState as useState9
|
|
2390
|
+
} from "react";
|
|
2391
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2392
|
+
var MejiroNotationHighlighter = forwardRef2(function MejiroNotationHighlighter2({
|
|
2393
|
+
value,
|
|
2394
|
+
onChange,
|
|
2395
|
+
dialect = "mejiro",
|
|
2396
|
+
wrapperClassName,
|
|
2397
|
+
wrapperStyle,
|
|
2398
|
+
className,
|
|
2399
|
+
style,
|
|
2400
|
+
onScroll,
|
|
2401
|
+
onCompositionStart,
|
|
2402
|
+
onCompositionEnd,
|
|
2403
|
+
...rest
|
|
2404
|
+
}, ref) {
|
|
2405
|
+
const textareaRef = useRef11(null);
|
|
2406
|
+
const overlayRef = useRef11(null);
|
|
2407
|
+
useImperativeHandle2(ref, () => textareaRef.current, []);
|
|
2408
|
+
const [isComposing, setIsComposing] = useState9(false);
|
|
2409
|
+
const lastSegmentsRef = useRef11(null);
|
|
2410
|
+
const segments = useMemo6(() => {
|
|
2411
|
+
if (isComposing && lastSegmentsRef.current) return lastSegmentsRef.current;
|
|
2412
|
+
const next = buildSegments(value, dialect);
|
|
2413
|
+
lastSegmentsRef.current = next;
|
|
2414
|
+
return next;
|
|
2415
|
+
}, [value, dialect, isComposing]);
|
|
2416
|
+
return /* @__PURE__ */ jsxs10(
|
|
2417
|
+
"div",
|
|
2418
|
+
{
|
|
2419
|
+
className: `mejiro-notation-highlighter${wrapperClassName ? ` ${wrapperClassName}` : ""}`,
|
|
2420
|
+
style: wrapperStyle,
|
|
2421
|
+
children: [
|
|
2422
|
+
/* @__PURE__ */ jsxs10(
|
|
2423
|
+
"div",
|
|
2424
|
+
{
|
|
2425
|
+
ref: overlayRef,
|
|
2426
|
+
className: "mejiro-notation-overlay",
|
|
2427
|
+
"aria-hidden": "true",
|
|
2428
|
+
children: [
|
|
2429
|
+
segments.map((segment) => /* @__PURE__ */ jsx15(
|
|
2430
|
+
"span",
|
|
2431
|
+
{
|
|
2432
|
+
className: segment.kind ? `mejiro-notation-token mejiro-notation-${segment.kind}` : void 0,
|
|
2433
|
+
"data-token": segment.kind,
|
|
2434
|
+
children: segment.text
|
|
2435
|
+
},
|
|
2436
|
+
segment.key
|
|
2437
|
+
)),
|
|
2438
|
+
"\u200B"
|
|
2439
|
+
]
|
|
2440
|
+
}
|
|
2441
|
+
),
|
|
2442
|
+
/* @__PURE__ */ jsx15(
|
|
2443
|
+
"textarea",
|
|
2444
|
+
{
|
|
2445
|
+
...rest,
|
|
2446
|
+
ref: textareaRef,
|
|
2447
|
+
className: `mejiro-notation-textarea${className ? ` ${className}` : ""}`,
|
|
2448
|
+
style,
|
|
2449
|
+
value,
|
|
2450
|
+
onChange: (event) => onChange(event.target.value),
|
|
2451
|
+
onCompositionStart: (event) => {
|
|
2452
|
+
setIsComposing(true);
|
|
2453
|
+
onCompositionStart?.(event);
|
|
2454
|
+
},
|
|
2455
|
+
onCompositionEnd: (event) => {
|
|
2456
|
+
setIsComposing(false);
|
|
2457
|
+
onCompositionEnd?.(event);
|
|
2458
|
+
},
|
|
2459
|
+
onScroll: (event) => {
|
|
2460
|
+
if (overlayRef.current) {
|
|
2461
|
+
overlayRef.current.scrollTop = event.currentTarget.scrollTop;
|
|
2462
|
+
overlayRef.current.scrollLeft = event.currentTarget.scrollLeft;
|
|
2463
|
+
}
|
|
2464
|
+
onScroll?.(event);
|
|
2465
|
+
},
|
|
2466
|
+
spellCheck: false
|
|
2467
|
+
}
|
|
2468
|
+
)
|
|
2469
|
+
]
|
|
2470
|
+
}
|
|
2471
|
+
);
|
|
2472
|
+
});
|
|
2473
|
+
function buildSegments(text, dialect) {
|
|
2474
|
+
const tokens = tokenizeManuscriptSource(text, dialect);
|
|
2475
|
+
const segments = [];
|
|
2476
|
+
let cursor = 0;
|
|
2477
|
+
for (const [i, token] of tokens.entries()) {
|
|
2478
|
+
if (token.start > cursor) {
|
|
2479
|
+
segments.push({ key: `t-${i}-pre`, text: text.slice(cursor, token.start) });
|
|
2480
|
+
}
|
|
2481
|
+
segments.push({
|
|
2482
|
+
key: `t-${i}`,
|
|
2483
|
+
text: text.slice(token.start, token.end),
|
|
2484
|
+
kind: token.kind
|
|
2485
|
+
});
|
|
2486
|
+
cursor = token.end;
|
|
2487
|
+
}
|
|
2488
|
+
if (cursor < text.length) {
|
|
2489
|
+
segments.push({ key: "tail", text: text.slice(cursor) });
|
|
2490
|
+
}
|
|
2491
|
+
if (segments.length === 0) {
|
|
2492
|
+
segments.push({ key: "empty", text });
|
|
2493
|
+
}
|
|
2494
|
+
return segments;
|
|
2495
|
+
}
|
|
2458
2496
|
|
|
2459
2497
|
// src/useManuscriptDraft.ts
|
|
2460
|
-
import { useCallback as useCallback8, useEffect as useEffect8, useRef as
|
|
2498
|
+
import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef12, useState as useState10 } from "react";
|
|
2461
2499
|
var DEFAULT_DELAY = 800;
|
|
2462
|
-
function defaultChapter(index) {
|
|
2463
|
-
return { id: `chapter-${Date.now()}-${index}`, title:
|
|
2500
|
+
function defaultChapter(index, titleFor = (i) => `\u7B2C${i + 1}\u8A71`, bodyFor = () => "") {
|
|
2501
|
+
return { id: `chapter-${Date.now()}-${index}`, title: titleFor(index), body: bodyFor(index) };
|
|
2464
2502
|
}
|
|
2465
2503
|
function useManuscriptDraft(options = {}) {
|
|
2466
|
-
const {
|
|
2467
|
-
|
|
2468
|
-
|
|
2504
|
+
const {
|
|
2505
|
+
onAutosave,
|
|
2506
|
+
autosaveDelay = DEFAULT_DELAY,
|
|
2507
|
+
autosavePayload,
|
|
2508
|
+
autosaveKey,
|
|
2509
|
+
defaultChapterTitle,
|
|
2510
|
+
defaultChapterBody
|
|
2511
|
+
} = options;
|
|
2512
|
+
const titleForRef = useRef12(defaultChapterTitle);
|
|
2513
|
+
titleForRef.current = defaultChapterTitle;
|
|
2514
|
+
const bodyForRef = useRef12(defaultChapterBody);
|
|
2515
|
+
bodyForRef.current = defaultChapterBody;
|
|
2516
|
+
const [chapters, setChaptersState] = useState10(
|
|
2517
|
+
() => options.initialChapters?.length ? options.initialChapters : [defaultChapter(0, defaultChapterTitle, defaultChapterBody)]
|
|
2469
2518
|
);
|
|
2470
|
-
const [selected, setSelectedState] =
|
|
2471
|
-
const
|
|
2519
|
+
const [selected, setSelectedState] = useState10(0);
|
|
2520
|
+
const [autosaveError, setAutosaveError] = useState10(null);
|
|
2521
|
+
const saveRef = useRef12(onAutosave);
|
|
2472
2522
|
saveRef.current = onAutosave;
|
|
2473
|
-
const
|
|
2523
|
+
const payloadRef = useRef12(autosavePayload);
|
|
2524
|
+
payloadRef.current = autosavePayload;
|
|
2525
|
+
const chaptersRef = useRef12(chapters);
|
|
2526
|
+
chaptersRef.current = chapters;
|
|
2527
|
+
const didMountRef = useRef12(false);
|
|
2528
|
+
const dirtyRef = useRef12(false);
|
|
2529
|
+
const mountedRef = useRef12(true);
|
|
2530
|
+
const flushAutosave = useCallback8(() => {
|
|
2531
|
+
const callback = saveRef.current;
|
|
2532
|
+
if (!(callback && dirtyRef.current)) return;
|
|
2533
|
+
dirtyRef.current = false;
|
|
2534
|
+
const payload = payloadRef.current ? payloadRef.current(chaptersRef.current) : chaptersRef.current;
|
|
2535
|
+
void Promise.resolve(callback(payload)).catch((err) => {
|
|
2536
|
+
if (!mountedRef.current) return;
|
|
2537
|
+
setAutosaveError(err instanceof Error ? err : new Error(String(err)));
|
|
2538
|
+
});
|
|
2539
|
+
}, []);
|
|
2474
2540
|
useEffect8(() => {
|
|
2475
2541
|
if (!didMountRef.current) {
|
|
2476
2542
|
didMountRef.current = true;
|
|
2477
2543
|
return void 0;
|
|
2478
2544
|
}
|
|
2479
|
-
|
|
2480
|
-
|
|
2545
|
+
if (!saveRef.current) return void 0;
|
|
2546
|
+
dirtyRef.current = true;
|
|
2547
|
+
setAutosaveError(null);
|
|
2481
2548
|
const timer = setTimeout(() => {
|
|
2482
|
-
|
|
2549
|
+
flushAutosave();
|
|
2483
2550
|
}, autosaveDelay);
|
|
2484
2551
|
return () => clearTimeout(timer);
|
|
2485
|
-
}, [chapters, autosaveDelay]);
|
|
2552
|
+
}, [chapters, autosaveKey, autosaveDelay, flushAutosave]);
|
|
2553
|
+
useEffect8(() => {
|
|
2554
|
+
mountedRef.current = true;
|
|
2555
|
+
const handleBeforeUnload = () => flushAutosave();
|
|
2556
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
2557
|
+
return () => {
|
|
2558
|
+
flushAutosave();
|
|
2559
|
+
mountedRef.current = false;
|
|
2560
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
2561
|
+
};
|
|
2562
|
+
}, [flushAutosave]);
|
|
2486
2563
|
const setSelected = useCallback8(
|
|
2487
2564
|
(index) => {
|
|
2488
2565
|
setSelectedState(() => Math.max(0, Math.min(index, chapters.length - 1)));
|
|
@@ -2491,7 +2568,7 @@ function useManuscriptDraft(options = {}) {
|
|
|
2491
2568
|
);
|
|
2492
2569
|
const setChapters = useCallback8(
|
|
2493
2570
|
(next) => {
|
|
2494
|
-
const normalized = next.length ? next : [defaultChapter(0)];
|
|
2571
|
+
const normalized = next.length ? next : [defaultChapter(0, titleForRef.current, bodyForRef.current)];
|
|
2495
2572
|
setChaptersState(normalized);
|
|
2496
2573
|
setSelectedState((current) => {
|
|
2497
2574
|
const selectedId = chapters[current]?.id;
|
|
@@ -2508,7 +2585,7 @@ function useManuscriptDraft(options = {}) {
|
|
|
2508
2585
|
}, []);
|
|
2509
2586
|
const addChapter = useCallback8((chapter = {}) => {
|
|
2510
2587
|
setChaptersState((current) => {
|
|
2511
|
-
const generated = defaultChapter(current.length);
|
|
2588
|
+
const generated = defaultChapter(current.length, titleForRef.current, bodyForRef.current);
|
|
2512
2589
|
const next = [
|
|
2513
2590
|
...current,
|
|
2514
2591
|
{
|
|
@@ -2557,12 +2634,14 @@ function useManuscriptDraft(options = {}) {
|
|
|
2557
2634
|
patchChapter,
|
|
2558
2635
|
addChapter,
|
|
2559
2636
|
removeChapter,
|
|
2560
|
-
reorderChapters
|
|
2637
|
+
reorderChapters,
|
|
2638
|
+
autosaveError,
|
|
2639
|
+
flushAutosave
|
|
2561
2640
|
};
|
|
2562
2641
|
}
|
|
2563
2642
|
|
|
2564
2643
|
// src/MejiroManuscriptEditor.tsx
|
|
2565
|
-
import { jsx as
|
|
2644
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2566
2645
|
function downloadEpub(buffer, title) {
|
|
2567
2646
|
const url = URL.createObjectURL(new Blob([buffer], { type: "application/epub+zip" }));
|
|
2568
2647
|
const a = document.createElement("a");
|
|
@@ -2614,14 +2693,14 @@ function MejiroManuscriptEditor({
|
|
|
2614
2693
|
onExport
|
|
2615
2694
|
}) {
|
|
2616
2695
|
const messages = useI18n();
|
|
2617
|
-
const coverInputRef =
|
|
2618
|
-
const bodyTextareaRef =
|
|
2696
|
+
const coverInputRef = useRef13(null);
|
|
2697
|
+
const bodyTextareaRef = useRef13(null);
|
|
2619
2698
|
const titleControlled = onTitleChange !== void 0;
|
|
2620
2699
|
const authorControlled = onAuthorChange !== void 0;
|
|
2621
2700
|
const coverControlled = onCoverChange !== void 0;
|
|
2622
|
-
const [titleState, setTitleState] =
|
|
2623
|
-
const [authorState, setAuthorState] =
|
|
2624
|
-
const [coverState, setCoverState] =
|
|
2701
|
+
const [titleState, setTitleState] = useState11(titleProp ?? messages.manuscriptDefaultTitle);
|
|
2702
|
+
const [authorState, setAuthorState] = useState11(authorProp ?? "");
|
|
2703
|
+
const [coverState, setCoverState] = useState11(coverProp ?? null);
|
|
2625
2704
|
const title = titleControlled ? titleProp ?? "" : titleState;
|
|
2626
2705
|
const author = authorControlled ? authorProp ?? "" : authorState;
|
|
2627
2706
|
const cover = coverControlled ? coverProp ?? null : coverState;
|
|
@@ -2658,7 +2737,10 @@ function MejiroManuscriptEditor({
|
|
|
2658
2737
|
const draft = useManuscriptDraft({
|
|
2659
2738
|
initialChapters: initialChapters?.length ? initialChapters : [defaultChapter2(messages)],
|
|
2660
2739
|
onAutosave,
|
|
2661
|
-
|
|
2740
|
+
autosavePayload: (savedChapters) => ({ title, author, cover, chapters: savedChapters }),
|
|
2741
|
+
autosaveKey: `${title}\0${author}\0${cover?.name ?? ""}\0${cover?.size ?? 0}\0${cover?.lastModified ?? 0}`,
|
|
2742
|
+
autosaveDelay,
|
|
2743
|
+
defaultChapterTitle: (index) => format(messages.manuscriptDefaultChapterTitle, { n: index + 1 })
|
|
2662
2744
|
});
|
|
2663
2745
|
const {
|
|
2664
2746
|
chapters,
|
|
@@ -2670,7 +2752,7 @@ function MejiroManuscriptEditor({
|
|
|
2670
2752
|
reorderChapters
|
|
2671
2753
|
} = draft;
|
|
2672
2754
|
const current = chapters[selected] ?? chapters[0];
|
|
2673
|
-
const [draggingIndex, setDraggingIndex] =
|
|
2755
|
+
const [draggingIndex, setDraggingIndex] = useState11(null);
|
|
2674
2756
|
function wrapSelection(open, close) {
|
|
2675
2757
|
const el = bodyTextareaRef.current;
|
|
2676
2758
|
if (!el) return;
|
|
@@ -2708,8 +2790,8 @@ function MejiroManuscriptEditor({
|
|
|
2708
2790
|
onExport?.(buffer);
|
|
2709
2791
|
downloadEpub(buffer, title);
|
|
2710
2792
|
}, [assetResolver, author, chapters, cover, messages.untitled, onExport, title]);
|
|
2711
|
-
return /* @__PURE__ */
|
|
2712
|
-
/* @__PURE__ */
|
|
2793
|
+
return /* @__PURE__ */ jsxs11("div", { className: "mejiro-editor mejiro-manuscript-editor", children: [
|
|
2794
|
+
/* @__PURE__ */ jsx16("main", { className: "mejiro-editor-preview", children: /* @__PURE__ */ jsx16(
|
|
2713
2795
|
MejiroReader,
|
|
2714
2796
|
{
|
|
2715
2797
|
subtitle: messages.manuscriptPreviewSubtitle,
|
|
@@ -2727,18 +2809,19 @@ function MejiroManuscriptEditor({
|
|
|
2727
2809
|
enableImageOverlay: false
|
|
2728
2810
|
}
|
|
2729
2811
|
) }),
|
|
2730
|
-
/* @__PURE__ */
|
|
2731
|
-
/* @__PURE__ */
|
|
2732
|
-
/* @__PURE__ */
|
|
2733
|
-
/* @__PURE__ */
|
|
2734
|
-
/* @__PURE__ */
|
|
2812
|
+
/* @__PURE__ */ jsxs11("aside", { className: "mejiro-editor-panel", children: [
|
|
2813
|
+
/* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-head", children: [
|
|
2814
|
+
/* @__PURE__ */ jsx16("span", { children: messages.manuscriptTitle }),
|
|
2815
|
+
/* @__PURE__ */ jsx16("strong", { children: title }),
|
|
2816
|
+
/* @__PURE__ */ jsx16("small", { children: messages.manuscriptRubyHint })
|
|
2735
2817
|
] }),
|
|
2736
|
-
/* @__PURE__ */
|
|
2737
|
-
|
|
2738
|
-
/* @__PURE__ */
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
/* @__PURE__ */
|
|
2818
|
+
draft.autosaveError && /* @__PURE__ */ jsx16("div", { className: "mejiro-editor-error", children: draft.autosaveError.message }),
|
|
2819
|
+
/* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-section", children: [
|
|
2820
|
+
/* @__PURE__ */ jsx16("span", { className: "mejiro-editor-label", children: messages.manuscriptMetadata }),
|
|
2821
|
+
/* @__PURE__ */ jsx16("input", { value: title, onChange: (event) => setTitle(event.target.value) }),
|
|
2822
|
+
/* @__PURE__ */ jsx16("input", { value: author, onChange: (event) => setAuthor(event.target.value) }),
|
|
2823
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => coverInputRef.current?.click(), children: cover ? cover.name : messages.manuscriptChooseCoverImage }),
|
|
2824
|
+
/* @__PURE__ */ jsx16(
|
|
2742
2825
|
"input",
|
|
2743
2826
|
{
|
|
2744
2827
|
ref: coverInputRef,
|
|
@@ -2749,9 +2832,9 @@ function MejiroManuscriptEditor({
|
|
|
2749
2832
|
}
|
|
2750
2833
|
)
|
|
2751
2834
|
] }),
|
|
2752
|
-
/* @__PURE__ */
|
|
2753
|
-
/* @__PURE__ */
|
|
2754
|
-
/* @__PURE__ */
|
|
2835
|
+
/* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-section", children: [
|
|
2836
|
+
/* @__PURE__ */ jsx16("span", { className: "mejiro-editor-label", children: messages.manuscriptChapters }),
|
|
2837
|
+
/* @__PURE__ */ jsx16("div", { className: "mejiro-editor-paragraphs", children: chapters.map((chapter, index) => /* @__PURE__ */ jsxs11(
|
|
2755
2838
|
"button",
|
|
2756
2839
|
{
|
|
2757
2840
|
type: "button",
|
|
@@ -2780,14 +2863,14 @@ function MejiroManuscriptEditor({
|
|
|
2780
2863
|
},
|
|
2781
2864
|
"data-dragging": draggingIndex === index ? "" : void 0,
|
|
2782
2865
|
children: [
|
|
2783
|
-
/* @__PURE__ */
|
|
2784
|
-
/* @__PURE__ */
|
|
2866
|
+
/* @__PURE__ */ jsx16("span", { children: format(messages.chapterN, { n: index + 1 }) }),
|
|
2867
|
+
/* @__PURE__ */ jsx16("strong", { children: chapter.title || messages.untitled })
|
|
2785
2868
|
]
|
|
2786
2869
|
},
|
|
2787
2870
|
chapter.id
|
|
2788
2871
|
)) }),
|
|
2789
|
-
/* @__PURE__ */
|
|
2790
|
-
/* @__PURE__ */
|
|
2872
|
+
/* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-grid", children: [
|
|
2873
|
+
/* @__PURE__ */ jsx16(
|
|
2791
2874
|
"button",
|
|
2792
2875
|
{
|
|
2793
2876
|
type: "button",
|
|
@@ -2799,138 +2882,41 @@ function MejiroManuscriptEditor({
|
|
|
2799
2882
|
children: messages.manuscriptAddChapter
|
|
2800
2883
|
}
|
|
2801
2884
|
),
|
|
2802
|
-
/* @__PURE__ */
|
|
2885
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => removeChapter(selected), children: messages.manuscriptRemove })
|
|
2803
2886
|
] })
|
|
2804
2887
|
] }),
|
|
2805
|
-
current && /* @__PURE__ */
|
|
2806
|
-
/* @__PURE__ */
|
|
2807
|
-
/* @__PURE__ */
|
|
2888
|
+
current && /* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-section", children: [
|
|
2889
|
+
/* @__PURE__ */ jsx16("span", { className: "mejiro-editor-label", children: messages.manuscriptDraft }),
|
|
2890
|
+
/* @__PURE__ */ jsx16(
|
|
2808
2891
|
"input",
|
|
2809
2892
|
{
|
|
2810
2893
|
value: current.title,
|
|
2811
2894
|
onChange: (event) => patchChapter(selected, { title: event.target.value })
|
|
2812
2895
|
}
|
|
2813
2896
|
),
|
|
2814
|
-
/* @__PURE__ */
|
|
2815
|
-
/* @__PURE__ */
|
|
2816
|
-
/* @__PURE__ */
|
|
2817
|
-
/* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2897
|
+
/* @__PURE__ */ jsxs11("div", { className: "mejiro-editor-grid mejiro-editor-notation", children: [
|
|
2898
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => wrapSelection("\u300A\u300A", "\u300B\u300B"), children: messages.manuscriptEmphasisDots }),
|
|
2899
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => wrapSelection("\u3014", "\u3015"), children: messages.manuscriptTcy }),
|
|
2900
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => wrapSelection("*", "*"), children: messages.manuscriptEm }),
|
|
2901
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: () => wrapSelection("**", "**"), children: messages.manuscriptStrong })
|
|
2819
2902
|
] }),
|
|
2820
|
-
/* @__PURE__ */
|
|
2821
|
-
|
|
2903
|
+
/* @__PURE__ */ jsx16(
|
|
2904
|
+
MejiroNotationHighlighter,
|
|
2822
2905
|
{
|
|
2823
2906
|
ref: bodyTextareaRef,
|
|
2824
2907
|
className: "mejiro-editor-manuscript",
|
|
2825
2908
|
value: current.body,
|
|
2826
|
-
onChange: (
|
|
2909
|
+
onChange: (body) => patchChapter(selected, { body })
|
|
2827
2910
|
}
|
|
2828
2911
|
)
|
|
2829
2912
|
] }),
|
|
2830
|
-
/* @__PURE__ */
|
|
2913
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "mejiro-editor-export", onClick: () => void exportEpub(), children: messages.editorExportEpub })
|
|
2831
2914
|
] })
|
|
2832
2915
|
] });
|
|
2833
2916
|
}
|
|
2834
2917
|
|
|
2835
|
-
// src/MejiroNotationHighlighter.tsx
|
|
2836
|
-
import { tokenizeManuscriptSource } from "@libraz/mejiro";
|
|
2837
|
-
import {
|
|
2838
|
-
forwardRef as forwardRef2,
|
|
2839
|
-
useImperativeHandle as useImperativeHandle2,
|
|
2840
|
-
useMemo as useMemo5,
|
|
2841
|
-
useRef as useRef13
|
|
2842
|
-
} from "react";
|
|
2843
|
-
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2844
|
-
var MejiroNotationHighlighter = forwardRef2(function MejiroNotationHighlighter2({
|
|
2845
|
-
value,
|
|
2846
|
-
onChange,
|
|
2847
|
-
dialect = "mejiro",
|
|
2848
|
-
wrapperClassName,
|
|
2849
|
-
wrapperStyle,
|
|
2850
|
-
className,
|
|
2851
|
-
style,
|
|
2852
|
-
onScroll,
|
|
2853
|
-
...rest
|
|
2854
|
-
}, ref) {
|
|
2855
|
-
const textareaRef = useRef13(null);
|
|
2856
|
-
const overlayRef = useRef13(null);
|
|
2857
|
-
useImperativeHandle2(ref, () => textareaRef.current, []);
|
|
2858
|
-
const segments = useMemo5(() => buildSegments(value, dialect), [value, dialect]);
|
|
2859
|
-
return /* @__PURE__ */ jsxs13(
|
|
2860
|
-
"div",
|
|
2861
|
-
{
|
|
2862
|
-
className: `mejiro-notation-highlighter${wrapperClassName ? ` ${wrapperClassName}` : ""}`,
|
|
2863
|
-
style: wrapperStyle,
|
|
2864
|
-
children: [
|
|
2865
|
-
/* @__PURE__ */ jsxs13(
|
|
2866
|
-
"div",
|
|
2867
|
-
{
|
|
2868
|
-
ref: overlayRef,
|
|
2869
|
-
className: "mejiro-notation-overlay",
|
|
2870
|
-
"aria-hidden": "true",
|
|
2871
|
-
children: [
|
|
2872
|
-
segments.map((segment) => /* @__PURE__ */ jsx15(
|
|
2873
|
-
"span",
|
|
2874
|
-
{
|
|
2875
|
-
className: segment.kind ? `mejiro-notation-token mejiro-notation-${segment.kind}` : void 0,
|
|
2876
|
-
"data-token": segment.kind,
|
|
2877
|
-
children: segment.text
|
|
2878
|
-
},
|
|
2879
|
-
segment.key
|
|
2880
|
-
)),
|
|
2881
|
-
"\u200B"
|
|
2882
|
-
]
|
|
2883
|
-
}
|
|
2884
|
-
),
|
|
2885
|
-
/* @__PURE__ */ jsx15(
|
|
2886
|
-
"textarea",
|
|
2887
|
-
{
|
|
2888
|
-
...rest,
|
|
2889
|
-
ref: textareaRef,
|
|
2890
|
-
className: `mejiro-notation-textarea${className ? ` ${className}` : ""}`,
|
|
2891
|
-
style,
|
|
2892
|
-
value,
|
|
2893
|
-
onChange: (event) => onChange(event.target.value),
|
|
2894
|
-
onScroll: (event) => {
|
|
2895
|
-
if (overlayRef.current) {
|
|
2896
|
-
overlayRef.current.scrollTop = event.currentTarget.scrollTop;
|
|
2897
|
-
overlayRef.current.scrollLeft = event.currentTarget.scrollLeft;
|
|
2898
|
-
}
|
|
2899
|
-
onScroll?.(event);
|
|
2900
|
-
},
|
|
2901
|
-
spellCheck: false
|
|
2902
|
-
}
|
|
2903
|
-
)
|
|
2904
|
-
]
|
|
2905
|
-
}
|
|
2906
|
-
);
|
|
2907
|
-
});
|
|
2908
|
-
function buildSegments(text, dialect) {
|
|
2909
|
-
const tokens = tokenizeManuscriptSource(text, dialect);
|
|
2910
|
-
const segments = [];
|
|
2911
|
-
let cursor = 0;
|
|
2912
|
-
for (const [i, token] of tokens.entries()) {
|
|
2913
|
-
if (token.start > cursor) {
|
|
2914
|
-
segments.push({ key: `t-${i}-pre`, text: text.slice(cursor, token.start) });
|
|
2915
|
-
}
|
|
2916
|
-
segments.push({
|
|
2917
|
-
key: `t-${i}`,
|
|
2918
|
-
text: text.slice(token.start, token.end),
|
|
2919
|
-
kind: token.kind
|
|
2920
|
-
});
|
|
2921
|
-
cursor = token.end;
|
|
2922
|
-
}
|
|
2923
|
-
if (cursor < text.length) {
|
|
2924
|
-
segments.push({ key: "tail", text: text.slice(cursor) });
|
|
2925
|
-
}
|
|
2926
|
-
if (segments.length === 0) {
|
|
2927
|
-
segments.push({ key: "empty", text });
|
|
2928
|
-
}
|
|
2929
|
-
return segments;
|
|
2930
|
-
}
|
|
2931
|
-
|
|
2932
2918
|
// src/MejiroShelf.tsx
|
|
2933
|
-
import { jsx as
|
|
2919
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2934
2920
|
function MejiroShelf({
|
|
2935
2921
|
volumes,
|
|
2936
2922
|
currentId,
|
|
@@ -2939,26 +2925,26 @@ function MejiroShelf({
|
|
|
2939
2925
|
}) {
|
|
2940
2926
|
const messages = useI18n();
|
|
2941
2927
|
const resolvedTitle = title ?? messages.shelfTitle;
|
|
2942
|
-
return /* @__PURE__ */
|
|
2943
|
-
/* @__PURE__ */
|
|
2944
|
-
/* @__PURE__ */
|
|
2928
|
+
return /* @__PURE__ */ jsxs12("section", { className: "mejiro-shelf", "aria-label": resolvedTitle, children: [
|
|
2929
|
+
/* @__PURE__ */ jsx17("header", { className: "mejiro-shelf-header", children: /* @__PURE__ */ jsx17("span", { className: "mejiro-shelf-title", children: resolvedTitle }) }),
|
|
2930
|
+
/* @__PURE__ */ jsx17("ul", { className: "mejiro-shelf-grid", children: volumes.map((v) => /* @__PURE__ */ jsx17("li", { className: "mejiro-shelf-item", children: /* @__PURE__ */ jsxs12(
|
|
2945
2931
|
"button",
|
|
2946
2932
|
{
|
|
2947
2933
|
type: "button",
|
|
2948
2934
|
className: `mejiro-shelf-card${v.id === currentId ? " is-active" : ""}`,
|
|
2949
2935
|
onClick: () => onSelect?.(v),
|
|
2950
2936
|
children: [
|
|
2951
|
-
v.cover ? /* @__PURE__ */
|
|
2937
|
+
v.cover ? /* @__PURE__ */ jsx17(
|
|
2952
2938
|
"span",
|
|
2953
2939
|
{
|
|
2954
2940
|
className: "mejiro-shelf-cover",
|
|
2955
2941
|
style: { backgroundImage: `url(${JSON.stringify(v.cover)})` },
|
|
2956
2942
|
"aria-hidden": "true"
|
|
2957
2943
|
}
|
|
2958
|
-
) : /* @__PURE__ */
|
|
2959
|
-
/* @__PURE__ */
|
|
2960
|
-
/* @__PURE__ */
|
|
2961
|
-
v.author && /* @__PURE__ */
|
|
2944
|
+
) : /* @__PURE__ */ jsx17("span", { className: "mejiro-shelf-cover mejiro-shelf-cover--blank", "aria-hidden": "true" }),
|
|
2945
|
+
/* @__PURE__ */ jsxs12("span", { className: "mejiro-shelf-meta", children: [
|
|
2946
|
+
/* @__PURE__ */ jsx17("span", { className: "mejiro-shelf-label", children: v.label }),
|
|
2947
|
+
v.author && /* @__PURE__ */ jsx17("span", { className: "mejiro-shelf-author", children: v.author })
|
|
2962
2948
|
] })
|
|
2963
2949
|
]
|
|
2964
2950
|
}
|
|
@@ -2967,8 +2953,8 @@ function MejiroShelf({
|
|
|
2967
2953
|
}
|
|
2968
2954
|
|
|
2969
2955
|
// src/MejiroToc.tsx
|
|
2970
|
-
import { useMemo as
|
|
2971
|
-
import { jsx as
|
|
2956
|
+
import { useMemo as useMemo7, useState as useState12 } from "react";
|
|
2957
|
+
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2972
2958
|
function buildEntries(epub, messages) {
|
|
2973
2959
|
return epub.chapters.map((ch, i) => {
|
|
2974
2960
|
const title = ch.title ?? format(messages.chapterN, { n: i + 1 });
|
|
@@ -2987,9 +2973,9 @@ function MejiroToc({
|
|
|
2987
2973
|
const messages = useI18n();
|
|
2988
2974
|
const resolvedTitle = title ?? messages.tocTitle;
|
|
2989
2975
|
const resolvedSearchPlaceholder = searchPlaceholder ?? messages.tocSearchPlaceholder;
|
|
2990
|
-
const [query, setQuery] =
|
|
2991
|
-
const entries =
|
|
2992
|
-
const filtered =
|
|
2976
|
+
const [query, setQuery] = useState12("");
|
|
2977
|
+
const entries = useMemo7(() => buildEntries(epub, messages), [epub, messages]);
|
|
2978
|
+
const filtered = useMemo7(() => {
|
|
2993
2979
|
if (!query) return entries;
|
|
2994
2980
|
const needle = query.toLowerCase();
|
|
2995
2981
|
return entries.filter(
|
|
@@ -2997,12 +2983,12 @@ function MejiroToc({
|
|
|
2997
2983
|
);
|
|
2998
2984
|
}, [entries, query]);
|
|
2999
2985
|
const activeIndex = currentAnchor?.chapter ?? -1;
|
|
3000
|
-
return /* @__PURE__ */
|
|
3001
|
-
/* @__PURE__ */
|
|
3002
|
-
/* @__PURE__ */
|
|
3003
|
-
epub.author && /* @__PURE__ */
|
|
2986
|
+
return /* @__PURE__ */ jsxs13("nav", { className: "mejiro-toc", "aria-label": resolvedTitle, children: [
|
|
2987
|
+
/* @__PURE__ */ jsxs13("header", { className: "mejiro-toc-header", children: [
|
|
2988
|
+
/* @__PURE__ */ jsx18("span", { className: "mejiro-toc-title", children: resolvedTitle }),
|
|
2989
|
+
epub.author && /* @__PURE__ */ jsx18("span", { className: "mejiro-toc-subtitle", children: epub.author })
|
|
3004
2990
|
] }),
|
|
3005
|
-
searchable && /* @__PURE__ */
|
|
2991
|
+
searchable && /* @__PURE__ */ jsx18("div", { className: "mejiro-toc-search", children: /* @__PURE__ */ jsx18(
|
|
3006
2992
|
"input",
|
|
3007
2993
|
{
|
|
3008
2994
|
type: "search",
|
|
@@ -3012,8 +2998,8 @@ function MejiroToc({
|
|
|
3012
2998
|
"aria-label": resolvedSearchPlaceholder
|
|
3013
2999
|
}
|
|
3014
3000
|
) }),
|
|
3015
|
-
/* @__PURE__ */
|
|
3016
|
-
/* @__PURE__ */
|
|
3001
|
+
/* @__PURE__ */ jsx18("ol", { className: "mejiro-toc-list", children: filtered.map((entry) => /* @__PURE__ */ jsxs13("li", { className: "mejiro-toc-item", children: [
|
|
3002
|
+
/* @__PURE__ */ jsxs13(
|
|
3017
3003
|
"button",
|
|
3018
3004
|
{
|
|
3019
3005
|
type: "button",
|
|
@@ -3021,58 +3007,37 @@ function MejiroToc({
|
|
|
3021
3007
|
"aria-current": entry.index === activeIndex ? "true" : void 0,
|
|
3022
3008
|
onClick: () => onSelect?.(entry.index),
|
|
3023
3009
|
children: [
|
|
3024
|
-
/* @__PURE__ */
|
|
3025
|
-
/* @__PURE__ */
|
|
3010
|
+
/* @__PURE__ */ jsx18("span", { className: "mejiro-toc-num", children: String(entry.index + 1).padStart(2, "0") }),
|
|
3011
|
+
/* @__PURE__ */ jsx18("span", { className: "mejiro-toc-label", children: entry.title })
|
|
3026
3012
|
]
|
|
3027
3013
|
}
|
|
3028
3014
|
),
|
|
3029
|
-
entry.headings.length > 0 && /* @__PURE__ */
|
|
3015
|
+
entry.headings.length > 0 && /* @__PURE__ */ jsx18("ul", { className: "mejiro-toc-subheads", children: entry.headings.slice(0, 5).map((h) => /* @__PURE__ */ jsx18("li", { className: "mejiro-toc-subhead", children: h }, h)) })
|
|
3030
3016
|
] }, entry.index)) }),
|
|
3031
|
-
filtered.length === 0 && /* @__PURE__ */
|
|
3017
|
+
filtered.length === 0 && /* @__PURE__ */ jsx18("div", { className: "mejiro-toc-empty", role: "status", children: format(messages.tocEmpty, { query }) })
|
|
3032
3018
|
] });
|
|
3033
3019
|
}
|
|
3034
3020
|
|
|
3035
3021
|
// src/useAnnotations.ts
|
|
3036
|
-
import {
|
|
3037
|
-
|
|
3022
|
+
import {
|
|
3023
|
+
createAnnotationId,
|
|
3024
|
+
parseAnnotations,
|
|
3025
|
+
serializeAnnotations,
|
|
3026
|
+
sortAnnotations
|
|
3027
|
+
} from "@libraz/mejiro";
|
|
3028
|
+
import { useCallback as useCallback10, useEffect as useEffect10, useRef as useRef14, useState as useState13 } from "react";
|
|
3038
3029
|
function resolveDefaultStorage() {
|
|
3039
3030
|
if (typeof globalThis === "undefined") return null;
|
|
3040
3031
|
const w = globalThis.localStorage;
|
|
3041
3032
|
return w ?? null;
|
|
3042
3033
|
}
|
|
3043
|
-
function parse(raw) {
|
|
3044
|
-
if (!raw) return [];
|
|
3045
|
-
try {
|
|
3046
|
-
const parsed = JSON.parse(raw);
|
|
3047
|
-
if (parsed && Array.isArray(parsed.annotations)) return parsed.annotations;
|
|
3048
|
-
} catch {
|
|
3049
|
-
}
|
|
3050
|
-
return [];
|
|
3051
|
-
}
|
|
3052
|
-
function serialize(annotations) {
|
|
3053
|
-
const payload = { version: STORAGE_VERSION, annotations: [...annotations] };
|
|
3054
|
-
return JSON.stringify(payload);
|
|
3055
|
-
}
|
|
3056
|
-
function sort(annotations) {
|
|
3057
|
-
return [...annotations].sort((a, b) => {
|
|
3058
|
-
if (a.chapter !== b.chapter) return a.chapter - b.chapter;
|
|
3059
|
-
if (a.start.paragraph !== b.start.paragraph) return a.start.paragraph - b.start.paragraph;
|
|
3060
|
-
return a.start.charIndex - b.start.charIndex;
|
|
3061
|
-
});
|
|
3062
|
-
}
|
|
3063
|
-
function makeId() {
|
|
3064
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
3065
|
-
return crypto.randomUUID();
|
|
3066
|
-
}
|
|
3067
|
-
return `ann-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
3068
|
-
}
|
|
3069
3034
|
function useAnnotations(options) {
|
|
3070
3035
|
const { key, throttleMs = 250 } = options;
|
|
3071
3036
|
const storage = options.storage ?? resolveDefaultStorage();
|
|
3072
|
-
const [annotations, setAnnotations] =
|
|
3037
|
+
const [annotations, setAnnotations] = useState13(() => {
|
|
3073
3038
|
if (!storage) return [];
|
|
3074
3039
|
try {
|
|
3075
|
-
return
|
|
3040
|
+
return sortAnnotations(parseAnnotations(storage.getItem(key)));
|
|
3076
3041
|
} catch {
|
|
3077
3042
|
return [];
|
|
3078
3043
|
}
|
|
@@ -3083,7 +3048,7 @@ function useAnnotations(options) {
|
|
|
3083
3048
|
return;
|
|
3084
3049
|
}
|
|
3085
3050
|
try {
|
|
3086
|
-
setAnnotations(
|
|
3051
|
+
setAnnotations(sortAnnotations(parseAnnotations(storage.getItem(key))));
|
|
3087
3052
|
} catch {
|
|
3088
3053
|
setAnnotations([]);
|
|
3089
3054
|
}
|
|
@@ -3103,7 +3068,7 @@ function useAnnotations(options) {
|
|
|
3103
3068
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3104
3069
|
timerRef.current = setTimeout(() => {
|
|
3105
3070
|
try {
|
|
3106
|
-
storage.setItem(key,
|
|
3071
|
+
storage.setItem(key, serializeAnnotations(next));
|
|
3107
3072
|
} catch {
|
|
3108
3073
|
}
|
|
3109
3074
|
}, throttleMs);
|
|
@@ -3116,11 +3081,11 @@ function useAnnotations(options) {
|
|
|
3116
3081
|
(input) => {
|
|
3117
3082
|
const annotation = {
|
|
3118
3083
|
...input,
|
|
3119
|
-
id: input.id ??
|
|
3084
|
+
id: input.id ?? createAnnotationId(),
|
|
3120
3085
|
createdAt: input.createdAt ?? Date.now()
|
|
3121
3086
|
};
|
|
3122
3087
|
setAnnotations((current) => {
|
|
3123
|
-
const next =
|
|
3088
|
+
const next = sortAnnotations([...current, annotation]);
|
|
3124
3089
|
commit(next);
|
|
3125
3090
|
return next;
|
|
3126
3091
|
});
|
|
@@ -3148,7 +3113,7 @@ function useAnnotations(options) {
|
|
|
3148
3113
|
return { ...annotation, ...patch, id };
|
|
3149
3114
|
});
|
|
3150
3115
|
if (!changed) return current;
|
|
3151
|
-
const sorted =
|
|
3116
|
+
const sorted = sortAnnotations(next);
|
|
3152
3117
|
commit(sorted);
|
|
3153
3118
|
return sorted;
|
|
3154
3119
|
});
|
|
@@ -3173,14 +3138,14 @@ function useAnnotations(options) {
|
|
|
3173
3138
|
import {
|
|
3174
3139
|
EditableEpub as EditableEpub2
|
|
3175
3140
|
} from "@libraz/mejiro/epub";
|
|
3176
|
-
import { useCallback as useCallback11, useEffect as useEffect11, useRef as useRef15, useState as
|
|
3141
|
+
import { useCallback as useCallback11, useEffect as useEffect11, useMemo as useMemo8, useRef as useRef15, useState as useState14 } from "react";
|
|
3177
3142
|
function useEditableEpub(options = {}) {
|
|
3178
|
-
const [editor, setEditor] =
|
|
3179
|
-
const [loading, setLoading] =
|
|
3180
|
-
const [exporting, setExporting] =
|
|
3181
|
-
const [error, setError] =
|
|
3182
|
-
const [revision, setRevision] =
|
|
3183
|
-
const [selection, setSelectionState] =
|
|
3143
|
+
const [editor, setEditor] = useState14(null);
|
|
3144
|
+
const [loading, setLoading] = useState14(false);
|
|
3145
|
+
const [exporting, setExporting] = useState14(false);
|
|
3146
|
+
const [error, setError] = useState14(null);
|
|
3147
|
+
const [revision, setRevision] = useState14(0);
|
|
3148
|
+
const [selection, setSelectionState] = useState14({
|
|
3184
3149
|
chapter: 0,
|
|
3185
3150
|
paragraph: 0
|
|
3186
3151
|
});
|
|
@@ -3268,7 +3233,10 @@ function useEditableEpub(options = {}) {
|
|
|
3268
3233
|
}, [options.defaultUrl, loadUrl]);
|
|
3269
3234
|
const book = editor?.book ?? null;
|
|
3270
3235
|
const selectedParagraph = book?.chapters[selection.chapter]?.paragraphs[selection.paragraph] ?? null;
|
|
3271
|
-
const previewBook =
|
|
3236
|
+
const previewBook = useMemo8(() => {
|
|
3237
|
+
void revision;
|
|
3238
|
+
return book ? cloneBook2(book) : null;
|
|
3239
|
+
}, [book, revision]);
|
|
3272
3240
|
const history = editor?.history ?? null;
|
|
3273
3241
|
const setSelection = useCallback11(
|
|
3274
3242
|
(nextSelection) => {
|
|
@@ -3391,20 +3359,22 @@ import {
|
|
|
3391
3359
|
EpubProject as EpubProject2,
|
|
3392
3360
|
parseEpub as parseEpub2
|
|
3393
3361
|
} from "@libraz/mejiro/epub";
|
|
3394
|
-
import { useCallback as useCallback12, useEffect as useEffect12, useMemo as
|
|
3362
|
+
import { useCallback as useCallback12, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef16, useState as useState15 } from "react";
|
|
3395
3363
|
function useEpubProject(options = {}) {
|
|
3396
|
-
const
|
|
3364
|
+
const defaultTitle = options.defaultChapterTitle;
|
|
3365
|
+
const defaultBody = options.defaultChapterBody;
|
|
3366
|
+
const [metadata, setMetadataState] = useState15({
|
|
3397
3367
|
title: "\u65B0\u3057\u3044\u4F5C\u54C1",
|
|
3398
3368
|
language: "ja",
|
|
3399
3369
|
...options.metadata
|
|
3400
3370
|
});
|
|
3401
|
-
const [chapters, setChaptersState] =
|
|
3402
|
-
options.chapters?.length ? options.chapters : [defaultChapter3(0)]
|
|
3371
|
+
const [chapters, setChaptersState] = useState15(
|
|
3372
|
+
options.chapters?.length ? options.chapters : [defaultChapter3(0, defaultTitle, defaultBody)]
|
|
3403
3373
|
);
|
|
3404
|
-
const [selectedChapter, setSelectedChapterState] =
|
|
3405
|
-
const [previewBook, setPreviewBook] =
|
|
3406
|
-
const [previewError, setPreviewError] =
|
|
3407
|
-
const [previewing, setPreviewing] =
|
|
3374
|
+
const [selectedChapter, setSelectedChapterState] = useState15(0);
|
|
3375
|
+
const [previewBook, setPreviewBook] = useState15(null);
|
|
3376
|
+
const [previewError, setPreviewError] = useState15(null);
|
|
3377
|
+
const [previewing, setPreviewing] = useState15(false);
|
|
3408
3378
|
const previewRequestIdRef = useRef16(0);
|
|
3409
3379
|
const onPreviewRef = useRef16(options.onPreview);
|
|
3410
3380
|
const onExportRef = useRef16(options.onExport);
|
|
@@ -3461,7 +3431,7 @@ function useEpubProject(options = {}) {
|
|
|
3461
3431
|
}, []);
|
|
3462
3432
|
const setChapters = useCallback12(
|
|
3463
3433
|
(next) => {
|
|
3464
|
-
const normalized = next.length ? next : [defaultChapter3(0)];
|
|
3434
|
+
const normalized = next.length ? next : [defaultChapter3(0, defaultTitle, defaultBody)];
|
|
3465
3435
|
setChaptersState(normalized);
|
|
3466
3436
|
setSelectedChapterState((current) => {
|
|
3467
3437
|
const selectedId = chapters[current]?.id;
|
|
@@ -3469,7 +3439,7 @@ function useEpubProject(options = {}) {
|
|
|
3469
3439
|
return nextIndex >= 0 ? nextIndex : Math.max(0, Math.min(current, normalized.length - 1));
|
|
3470
3440
|
});
|
|
3471
3441
|
},
|
|
3472
|
-
[chapters]
|
|
3442
|
+
[chapters, defaultBody, defaultTitle]
|
|
3473
3443
|
);
|
|
3474
3444
|
const setSelectedChapter = useCallback12(
|
|
3475
3445
|
(index) => {
|
|
@@ -3484,21 +3454,24 @@ function useEpubProject(options = {}) {
|
|
|
3484
3454
|
)
|
|
3485
3455
|
);
|
|
3486
3456
|
}, []);
|
|
3487
|
-
const addChapter = useCallback12(
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3457
|
+
const addChapter = useCallback12(
|
|
3458
|
+
(chapter = {}) => {
|
|
3459
|
+
setChaptersState((current) => {
|
|
3460
|
+
const generated = defaultChapter3(current.length, defaultTitle, defaultBody);
|
|
3461
|
+
const next = [
|
|
3462
|
+
...current,
|
|
3463
|
+
{
|
|
3464
|
+
id: chapter.id ?? generated.id,
|
|
3465
|
+
title: chapter.title ?? generated.title,
|
|
3466
|
+
body: chapter.body ?? generated.body
|
|
3467
|
+
}
|
|
3468
|
+
];
|
|
3469
|
+
setSelectedChapterState(next.length - 1);
|
|
3470
|
+
return next;
|
|
3471
|
+
});
|
|
3472
|
+
},
|
|
3473
|
+
[defaultBody, defaultTitle]
|
|
3474
|
+
);
|
|
3502
3475
|
const removeChapter = useCallback12(
|
|
3503
3476
|
(index = selectedChapter) => {
|
|
3504
3477
|
setChaptersState((current) => {
|
|
@@ -3536,7 +3509,7 @@ function useEpubProject(options = {}) {
|
|
|
3536
3509
|
onExportRef.current?.(buffer);
|
|
3537
3510
|
return buffer;
|
|
3538
3511
|
}, [buildProject]);
|
|
3539
|
-
return
|
|
3512
|
+
return useMemo9(
|
|
3540
3513
|
() => ({
|
|
3541
3514
|
metadata,
|
|
3542
3515
|
chapters,
|
|
@@ -3575,11 +3548,11 @@ function useEpubProject(options = {}) {
|
|
|
3575
3548
|
]
|
|
3576
3549
|
);
|
|
3577
3550
|
}
|
|
3578
|
-
function defaultChapter3(index) {
|
|
3551
|
+
function defaultChapter3(index, titleFor = (i) => i === 0 ? "\u7B2C\u4E00\u8A71" : `\u7B2C${i + 1}\u8A71`, bodyFor = (i) => i === 0 ? "\u3053\u308C\u306F\uFF5C\u6F22\u5B57\u300A\u304B\u3093\u3058\u300B\u306E\u30EB\u30D3\u4F8B\u3067\u3059\u3002\n\n\u672C\u6587\u3092\u3053\u3053\u306B\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002" : "") {
|
|
3579
3552
|
return {
|
|
3580
3553
|
id: `chapter-${Date.now()}-${index}`,
|
|
3581
|
-
title: index
|
|
3582
|
-
body: index
|
|
3554
|
+
title: titleFor(index),
|
|
3555
|
+
body: bodyFor(index)
|
|
3583
3556
|
};
|
|
3584
3557
|
}
|
|
3585
3558
|
|
|
@@ -3589,7 +3562,7 @@ import {
|
|
|
3589
3562
|
useCallback as useCallback13,
|
|
3590
3563
|
useEffect as useEffect13,
|
|
3591
3564
|
useRef as useRef17,
|
|
3592
|
-
useState as
|
|
3565
|
+
useState as useState16
|
|
3593
3566
|
} from "react";
|
|
3594
3567
|
function useImageOverlay(layout, spreadIdx, onUpdate, options) {
|
|
3595
3568
|
const defW = options?.defaultWidth ?? 120;
|
|
@@ -3597,7 +3570,7 @@ function useImageOverlay(layout, spreadIdx, onUpdate, options) {
|
|
|
3597
3570
|
const defX = options?.defaultX ?? 80;
|
|
3598
3571
|
const defY = options?.defaultY ?? 100;
|
|
3599
3572
|
const margin = options?.margin;
|
|
3600
|
-
const [imageRect, setImageRect] =
|
|
3573
|
+
const [imageRect, setImageRect] = useState16(null);
|
|
3601
3574
|
const rectRef = useRef17(imageRect);
|
|
3602
3575
|
rectRef.current = imageRect;
|
|
3603
3576
|
const layoutRef = useRef17(layout);
|
|
@@ -3719,14 +3692,14 @@ function useImageOverlay(layout, spreadIdx, onUpdate, options) {
|
|
|
3719
3692
|
}
|
|
3720
3693
|
|
|
3721
3694
|
// src/useLibrary.ts
|
|
3722
|
-
import { useCallback as useCallback14, useEffect as useEffect14, useMemo as
|
|
3695
|
+
import { useCallback as useCallback14, useEffect as useEffect14, useMemo as useMemo10, useState as useState17 } from "react";
|
|
3723
3696
|
function useLibrary(options) {
|
|
3724
3697
|
const { volumes, initialVolumeId, onChange } = options;
|
|
3725
3698
|
const initialIndex = initialVolumeId != null ? Math.max(
|
|
3726
3699
|
0,
|
|
3727
3700
|
volumes.findIndex((v) => v.id === initialVolumeId)
|
|
3728
3701
|
) : 0;
|
|
3729
|
-
const [currentId, setCurrentId] =
|
|
3702
|
+
const [currentId, setCurrentId] = useState17(
|
|
3730
3703
|
volumes.length > 0 ? volumes[initialIndex]?.id ?? volumes[0]?.id ?? null : null
|
|
3731
3704
|
);
|
|
3732
3705
|
useEffect14(() => {
|
|
@@ -3739,13 +3712,13 @@ function useLibrary(options) {
|
|
|
3739
3712
|
setCurrentId(fallback?.id ?? null);
|
|
3740
3713
|
if (fallback) onChange?.(fallback);
|
|
3741
3714
|
}, [currentId, volumes, onChange]);
|
|
3742
|
-
const index =
|
|
3715
|
+
const index = useMemo10(() => {
|
|
3743
3716
|
if (volumes.length === 0) return -1;
|
|
3744
3717
|
if (currentId == null) return 0;
|
|
3745
3718
|
const found = volumes.findIndex((v) => v.id === currentId);
|
|
3746
3719
|
return found >= 0 ? found : 0;
|
|
3747
3720
|
}, [currentId, volumes]);
|
|
3748
|
-
const current =
|
|
3721
|
+
const current = useMemo10(
|
|
3749
3722
|
() => index >= 0 && index < volumes.length ? volumes[index] : null,
|
|
3750
3723
|
[index, volumes]
|
|
3751
3724
|
);
|
|
@@ -3787,19 +3760,17 @@ function useLibrary(options) {
|
|
|
3787
3760
|
}
|
|
3788
3761
|
|
|
3789
3762
|
// src/useManuscriptLayout.ts
|
|
3790
|
-
import { useCallback as useCallback15, useEffect as useEffect15, useLayoutEffect as useLayoutEffect5, useRef as useRef18, useState as
|
|
3763
|
+
import { useCallback as useCallback15, useEffect as useEffect15, useLayoutEffect as useLayoutEffect5, useRef as useRef18, useState as useState18 } from "react";
|
|
3791
3764
|
function useManuscriptLayout(book, chapter, surface, options = {}) {
|
|
3792
3765
|
const dialect = options.dialect ?? "mejiro";
|
|
3793
3766
|
const enableResize = options.enableResize ?? true;
|
|
3794
3767
|
const resizeDebounce = options.resizeDebounce ?? 120;
|
|
3795
|
-
const [layout, setLayout] =
|
|
3796
|
-
const [pageWidth, setPageWidth] =
|
|
3797
|
-
const [pageHeight, setPageHeight] =
|
|
3798
|
-
const [contentHeight, setContentHeight] =
|
|
3799
|
-
const [elapsedMs, setElapsedMs] =
|
|
3800
|
-
const layoutRef = useRef18(null);
|
|
3768
|
+
const [layout, setLayout] = useState18(null);
|
|
3769
|
+
const [pageWidth, setPageWidth] = useState18(0);
|
|
3770
|
+
const [pageHeight, setPageHeight] = useState18(0);
|
|
3771
|
+
const [contentHeight, setContentHeight] = useState18(0);
|
|
3772
|
+
const [elapsedMs, setElapsedMs] = useState18(0);
|
|
3801
3773
|
const requestIdRef = useRef18(0);
|
|
3802
|
-
layoutRef.current = layout;
|
|
3803
3774
|
const recompute = useCallback15(async () => {
|
|
3804
3775
|
const requestId = ++requestIdRef.current;
|
|
3805
3776
|
if (!(chapter && surface.current)) {
|
|
@@ -3838,95 +3809,85 @@ function useManuscriptLayout(book, chapter, surface, options = {}) {
|
|
|
3838
3809
|
}, [recompute]);
|
|
3839
3810
|
useEffect15(() => {
|
|
3840
3811
|
if (!enableResize) return;
|
|
3812
|
+
const el = surface.current;
|
|
3813
|
+
if (!el) return;
|
|
3841
3814
|
let timer = null;
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
if (timer)
|
|
3815
|
+
let observed = false;
|
|
3816
|
+
const clear = () => {
|
|
3817
|
+
if (timer) {
|
|
3818
|
+
clearTimeout(timer);
|
|
3819
|
+
timer = null;
|
|
3820
|
+
}
|
|
3821
|
+
};
|
|
3822
|
+
const scheduleReflow = (immediate) => {
|
|
3823
|
+
clear();
|
|
3824
|
+
if (immediate) {
|
|
3825
|
+
void recompute();
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3845
3828
|
timer = setTimeout(() => {
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
setPageWidth(dims.pageWidth);
|
|
3849
|
-
setPageHeight(dims.pageHeight);
|
|
3850
|
-
setContentHeight(dims.contentHeight);
|
|
3851
|
-
layoutRef.current.resize({
|
|
3852
|
-
pageWidth: dims.pageWidth,
|
|
3853
|
-
lineWidth: dims.contentHeight - book.getOptions().fontSize * 0.5
|
|
3854
|
-
});
|
|
3829
|
+
timer = null;
|
|
3830
|
+
void recompute();
|
|
3855
3831
|
}, resizeDebounce);
|
|
3856
3832
|
};
|
|
3857
|
-
|
|
3833
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3834
|
+
const observer = new ResizeObserver(() => {
|
|
3835
|
+
const immediate = !observed;
|
|
3836
|
+
observed = true;
|
|
3837
|
+
scheduleReflow(immediate);
|
|
3838
|
+
});
|
|
3839
|
+
observer.observe(el);
|
|
3840
|
+
return () => {
|
|
3841
|
+
observer.disconnect();
|
|
3842
|
+
clear();
|
|
3843
|
+
};
|
|
3844
|
+
}
|
|
3845
|
+
const onWindowResize = () => scheduleReflow(false);
|
|
3846
|
+
window.addEventListener("resize", onWindowResize);
|
|
3858
3847
|
return () => {
|
|
3859
|
-
window.removeEventListener("resize",
|
|
3860
|
-
|
|
3848
|
+
window.removeEventListener("resize", onWindowResize);
|
|
3849
|
+
clear();
|
|
3861
3850
|
};
|
|
3862
|
-
}, [
|
|
3851
|
+
}, [surface, enableResize, resizeDebounce, recompute]);
|
|
3863
3852
|
return { layout, pageWidth, pageHeight, contentHeight, elapsedMs, recompute };
|
|
3864
3853
|
}
|
|
3865
3854
|
|
|
3866
3855
|
// src/useReadingPosition.ts
|
|
3867
|
-
import {
|
|
3868
|
-
|
|
3856
|
+
import {
|
|
3857
|
+
parseReadingPosition,
|
|
3858
|
+
serializeReadingPosition
|
|
3859
|
+
} from "@libraz/mejiro";
|
|
3860
|
+
import { useCallback as useCallback16, useEffect as useEffect16, useRef as useRef19, useState as useState19 } from "react";
|
|
3869
3861
|
function resolveDefaultStorage2() {
|
|
3870
3862
|
if (typeof globalThis === "undefined") return null;
|
|
3871
3863
|
const w = globalThis.localStorage;
|
|
3872
3864
|
return w ?? null;
|
|
3873
3865
|
}
|
|
3874
|
-
function parsePosition(raw) {
|
|
3875
|
-
if (!raw) return null;
|
|
3876
|
-
let parsed;
|
|
3877
|
-
try {
|
|
3878
|
-
parsed = JSON.parse(raw);
|
|
3879
|
-
} catch {
|
|
3880
|
-
return null;
|
|
3881
|
-
}
|
|
3882
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
3883
|
-
const p = parsed;
|
|
3884
|
-
if (typeof p.chapter !== "number") return null;
|
|
3885
|
-
if (p.version === STORAGE_VERSION2) {
|
|
3886
|
-
if (typeof p.paragraph !== "number" || typeof p.charIndex !== "number") return null;
|
|
3887
|
-
return { chapter: p.chapter, paragraph: p.paragraph, charIndex: p.charIndex };
|
|
3888
|
-
}
|
|
3889
|
-
if (typeof p.spreadIdx === "number") {
|
|
3890
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
3891
|
-
console.warn(
|
|
3892
|
-
"[mejiro] useReadingPosition: migrating legacy {chapter, spreadIdx} format. spreadIdx has been dropped because it does not survive reflow; the position now resumes at the start of the chapter. Persist new positions via save() to upgrade."
|
|
3893
|
-
);
|
|
3894
|
-
}
|
|
3895
|
-
return { chapter: p.chapter, paragraph: 0, charIndex: 0 };
|
|
3896
|
-
}
|
|
3897
|
-
return null;
|
|
3898
|
-
}
|
|
3899
|
-
function serializePosition(value) {
|
|
3900
|
-
const payload = {
|
|
3901
|
-
version: STORAGE_VERSION2,
|
|
3902
|
-
chapter: value.chapter,
|
|
3903
|
-
paragraph: value.paragraph,
|
|
3904
|
-
charIndex: value.charIndex
|
|
3905
|
-
};
|
|
3906
|
-
return JSON.stringify(payload);
|
|
3907
|
-
}
|
|
3908
3866
|
function useReadingPosition(options) {
|
|
3909
3867
|
const { key, throttleMs = 250 } = options;
|
|
3910
3868
|
const storage = options.storage ?? resolveDefaultStorage2();
|
|
3911
|
-
const [position, setPosition] =
|
|
3869
|
+
const [position, setPosition] = useState19(() => {
|
|
3912
3870
|
if (!storage) return null;
|
|
3913
3871
|
try {
|
|
3914
|
-
return
|
|
3872
|
+
return parseReadingPosition(storage.getItem(key));
|
|
3915
3873
|
} catch {
|
|
3916
3874
|
return null;
|
|
3917
3875
|
}
|
|
3918
3876
|
});
|
|
3877
|
+
const storageRef = useRef19(storage);
|
|
3878
|
+
storageRef.current = storage;
|
|
3919
3879
|
useEffect16(() => {
|
|
3920
|
-
|
|
3880
|
+
const currentStorage = storageRef.current;
|
|
3881
|
+
if (!currentStorage) {
|
|
3921
3882
|
setPosition(null);
|
|
3922
3883
|
return;
|
|
3923
3884
|
}
|
|
3924
3885
|
try {
|
|
3925
|
-
setPosition(
|
|
3886
|
+
setPosition(parseReadingPosition(currentStorage.getItem(key)));
|
|
3926
3887
|
} catch {
|
|
3927
3888
|
setPosition(null);
|
|
3928
3889
|
}
|
|
3929
|
-
}, [
|
|
3890
|
+
}, [key]);
|
|
3930
3891
|
const timerRef = useRef19(null);
|
|
3931
3892
|
useEffect16(
|
|
3932
3893
|
() => () => {
|
|
@@ -3939,30 +3900,32 @@ function useReadingPosition(options) {
|
|
|
3939
3900
|
const save = useCallback16(
|
|
3940
3901
|
(next) => {
|
|
3941
3902
|
setPosition(next);
|
|
3942
|
-
|
|
3903
|
+
const currentStorage = storageRef.current;
|
|
3904
|
+
if (currentStorage) {
|
|
3943
3905
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3944
3906
|
timerRef.current = setTimeout(() => {
|
|
3945
3907
|
try {
|
|
3946
|
-
|
|
3908
|
+
currentStorage.setItem(key, serializeReadingPosition(next));
|
|
3947
3909
|
} catch {
|
|
3948
3910
|
}
|
|
3949
3911
|
}, throttleMs);
|
|
3950
3912
|
}
|
|
3951
3913
|
onChangeRef.current?.(next);
|
|
3952
3914
|
},
|
|
3953
|
-
[
|
|
3915
|
+
[key, throttleMs]
|
|
3954
3916
|
);
|
|
3955
3917
|
const clear = useCallback16(() => {
|
|
3956
3918
|
setPosition(null);
|
|
3957
3919
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3958
|
-
|
|
3920
|
+
const currentStorage = storageRef.current;
|
|
3921
|
+
if (currentStorage) {
|
|
3959
3922
|
try {
|
|
3960
|
-
|
|
3923
|
+
currentStorage.removeItem(key);
|
|
3961
3924
|
} catch {
|
|
3962
3925
|
}
|
|
3963
3926
|
}
|
|
3964
3927
|
onChangeRef.current?.(null);
|
|
3965
|
-
}, [
|
|
3928
|
+
}, [key]);
|
|
3966
3929
|
return { position, save, clear };
|
|
3967
3930
|
}
|
|
3968
3931
|
|
|
@@ -3993,7 +3956,7 @@ export {
|
|
|
3993
3956
|
MejiroSpread,
|
|
3994
3957
|
MejiroStats,
|
|
3995
3958
|
MejiroToc,
|
|
3996
|
-
enMessages,
|
|
3959
|
+
enMessages2 as enMessages,
|
|
3997
3960
|
format,
|
|
3998
3961
|
jaMessages,
|
|
3999
3962
|
resolveMessages,
|