@libraz/mejiro
v0.9.2
Published
Japanese vertical text layout engine for the web — line breaking, kinsoku shori, hanging punctuation, ruby, EPUB parsing/authoring, and pagination
Maintainers
Readme
@libraz/mejiro
Japanese vertical text layout engine for the web. It handles line breaking, kinsoku shori, hanging punctuation, ruby, tate-chu-yoko, pagination, image exclusion, and EPUB parsing and authoring. The core has zero DOM dependencies. Pairs with @libraz/mejiro-react / @libraz/mejiro-vue for ready-to-use reader/editor components.
Install
npm install @libraz/mejiroQuick start
import { DEFAULT_HEADING_STYLES, MejiroBook } from '@libraz/mejiro/book';
import { parseEpub } from '@libraz/mejiro/epub';
const book = new MejiroBook({
fontFamily: '"Noto Serif JP"',
fontSize: 16,
lineSpacing: 1.8,
headingStyles: DEFAULT_HEADING_STYLES,
});
book.computePageSize(document.querySelector('.reader')!);
const epub = await parseEpub(epubBuffer);
const layout = await book.layoutChapter(epub.chapters[0]);
const spread = layout.getSpread(0);Subpath exports
| Import path | Description |
|---|---|
| @libraz/mejiro | Core: line breaking, kinsoku, hanging, ruby (preprocessRuby), tate-chu-yoko (preprocessTcy / buildTcyAnnotations), NFC normalization (normalizeText), pagination (paginate / getLineRanges), image exclusion, annotation / reading-position persistence, i18n message catalogs |
| @libraz/mejiro/browser | Font measurement (MejiroBrowser, CharMeasurer), ruby font derivation, image drag and resize sessions (createOverlayDragSession) |
| @libraz/mejiro/epub | EPUB parsing (parseEpub) with untrusted-archive resource limits, EditableEpub write-back, cloneEditableEpubBook / clampEditableEpubSelection, manuscript parsing (parseManuscript), EpubProject authoring |
| @libraz/mejiro/render | Layout → RenderPage data, paragraphClassName, static HTML (renderEpubStatic), stylesheets |
| @libraz/mejiro/book | High-level MejiroBook / ChapterLayout: pagination, full-text search (findText), reading anchors, layout snapshots, estimateReadingTime |
| @libraz/mejiro/image | Browser-side image decode / downscale helpers (prepareImage) |
| @libraz/mejiro/analysis | Optional morphological analyzer for analysis-driven line breaking (createSuzumeAnalyzer, backed by the optional peer @libraz/suzume) |
Stylesheets
Five stylesheets ship as separate subpaths, so a host app imports only what it renders:
| Import path | Purpose |
|---|---|
| @libraz/mejiro/render/mejiro.css | Base vertical text layout — required whenever RenderPage data is rendered |
| @libraz/mejiro/render/mejiro-reader.css | Reader chrome: header, spread frame, page navigation |
| @libraz/mejiro/render/mejiro-editor.css | Editor chrome: toolbars, inline editing, image overlays |
| @libraz/mejiro/render/mejiro-fonts.css | Optional Japanese webfont declarations |
| @libraz/mejiro/render/mejiro-print.css | Print / PDF output |
Untrusted EPUB archives
parseEpub() and parseEditableEpub() enforce resource limits by default, so a hostile
or malformed archive cannot exhaust memory: caps on compressed input size, entry count,
per-entry and total expanded size, and per-entry compression ratio. Limits are checked
against the bytes the decompressor really produces, not the sizes the archive declares
for itself, and reading stops as soon as a cap would be passed.
The defaults are exported as DEFAULT_EPUB_PARSE_LIMITS. In a trusted environment —
a build step over your own files, say — raise individual caps through
EpubParseOptions.limits:
import { parseEpub } from '@libraz/mejiro/epub';
const book = await parseEpub(buffer, { limits: { maxTotalBytes: 1024 * 1024 * 1024 } });