wolfy-reader 0.1.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.
Files changed (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/core/book.d.ts +75 -0
  4. package/dist/core/book.d.ts.map +1 -0
  5. package/dist/core/book.js +2 -0
  6. package/dist/core/book.js.map +1 -0
  7. package/dist/core/errors.d.ts +17 -0
  8. package/dist/core/errors.d.ts.map +1 -0
  9. package/dist/core/errors.js +29 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/format.d.ts +13 -0
  12. package/dist/core/format.d.ts.map +1 -0
  13. package/dist/core/format.js +2 -0
  14. package/dist/core/format.js.map +1 -0
  15. package/dist/core/graphemes.d.ts +36 -0
  16. package/dist/core/graphemes.d.ts.map +1 -0
  17. package/dist/core/graphemes.js +62 -0
  18. package/dist/core/graphemes.js.map +1 -0
  19. package/dist/core/index.d.ts +11 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +6 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/lookup.d.ts +10 -0
  24. package/dist/core/lookup.d.ts.map +1 -0
  25. package/dist/core/lookup.js +16 -0
  26. package/dist/core/lookup.js.map +1 -0
  27. package/dist/core/open.d.ts +12 -0
  28. package/dist/core/open.d.ts.map +1 -0
  29. package/dist/core/open.js +23 -0
  30. package/dist/core/open.js.map +1 -0
  31. package/dist/core/position.d.ts +121 -0
  32. package/dist/core/position.d.ts.map +1 -0
  33. package/dist/core/position.js +327 -0
  34. package/dist/core/position.js.map +1 -0
  35. package/dist/core/reading-text.d.ts +77 -0
  36. package/dist/core/reading-text.d.ts.map +1 -0
  37. package/dist/core/reading-text.js +144 -0
  38. package/dist/core/reading-text.js.map +1 -0
  39. package/dist/core/source.d.ts +17 -0
  40. package/dist/core/source.d.ts.map +1 -0
  41. package/dist/core/source.js +39 -0
  42. package/dist/core/source.js.map +1 -0
  43. package/dist/core/storage.d.ts +7 -0
  44. package/dist/core/storage.d.ts.map +1 -0
  45. package/dist/core/storage.js +2 -0
  46. package/dist/core/storage.js.map +1 -0
  47. package/dist/core/text.d.ts +18 -0
  48. package/dist/core/text.d.ts.map +1 -0
  49. package/dist/core/text.js +32 -0
  50. package/dist/core/text.js.map +1 -0
  51. package/dist/formats/epub/href.d.ts +14 -0
  52. package/dist/formats/epub/href.d.ts.map +1 -0
  53. package/dist/formats/epub/href.js +52 -0
  54. package/dist/formats/epub/href.js.map +1 -0
  55. package/dist/formats/epub/index.d.ts +3 -0
  56. package/dist/formats/epub/index.d.ts.map +1 -0
  57. package/dist/formats/epub/index.js +223 -0
  58. package/dist/formats/epub/index.js.map +1 -0
  59. package/dist/formats/epub/opf.d.ts +27 -0
  60. package/dist/formats/epub/opf.d.ts.map +1 -0
  61. package/dist/formats/epub/opf.js +110 -0
  62. package/dist/formats/epub/opf.js.map +1 -0
  63. package/dist/formats/epub/toc.d.ts +6 -0
  64. package/dist/formats/epub/toc.d.ts.map +1 -0
  65. package/dist/formats/epub/toc.js +88 -0
  66. package/dist/formats/epub/toc.js.map +1 -0
  67. package/dist/formats/fb2/index.d.ts +13 -0
  68. package/dist/formats/fb2/index.d.ts.map +1 -0
  69. package/dist/formats/fb2/index.js +317 -0
  70. package/dist/formats/fb2/index.js.map +1 -0
  71. package/dist/formats/index.d.ts +4 -0
  72. package/dist/formats/index.d.ts.map +1 -0
  73. package/dist/formats/index.js +4 -0
  74. package/dist/formats/index.js.map +1 -0
  75. package/dist/formats/text/index.d.ts +11 -0
  76. package/dist/formats/text/index.d.ts.map +1 -0
  77. package/dist/formats/text/index.js +201 -0
  78. package/dist/formats/text/index.js.map +1 -0
  79. package/dist/formats/xml.d.ts +33 -0
  80. package/dist/formats/xml.d.ts.map +1 -0
  81. package/dist/formats/xml.js +321 -0
  82. package/dist/formats/xml.js.map +1 -0
  83. package/dist/index.d.ts +27 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +28 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/layout/chunk.d.ts +51 -0
  88. package/dist/layout/chunk.d.ts.map +1 -0
  89. package/dist/layout/chunk.js +131 -0
  90. package/dist/layout/chunk.js.map +1 -0
  91. package/dist/layout/index.d.ts +238 -0
  92. package/dist/layout/index.d.ts.map +1 -0
  93. package/dist/layout/index.js +476 -0
  94. package/dist/layout/index.js.map +1 -0
  95. package/dist/reader/index.d.ts +231 -0
  96. package/dist/reader/index.d.ts.map +1 -0
  97. package/dist/reader/index.js +958 -0
  98. package/dist/reader/index.js.map +1 -0
  99. package/dist/reader/input.d.ts +69 -0
  100. package/dist/reader/input.d.ts.map +1 -0
  101. package/dist/reader/input.js +75 -0
  102. package/dist/reader/input.js.map +1 -0
  103. package/dist/search/extract.d.ts +51 -0
  104. package/dist/search/extract.d.ts.map +1 -0
  105. package/dist/search/extract.js +401 -0
  106. package/dist/search/extract.js.map +1 -0
  107. package/dist/search/index.d.ts +11 -0
  108. package/dist/search/index.d.ts.map +1 -0
  109. package/dist/search/index.js +11 -0
  110. package/dist/search/index.js.map +1 -0
  111. package/dist/search/matcher.d.ts +56 -0
  112. package/dist/search/matcher.d.ts.map +1 -0
  113. package/dist/search/matcher.js +128 -0
  114. package/dist/search/matcher.js.map +1 -0
  115. package/dist/search/normalize.d.ts +48 -0
  116. package/dist/search/normalize.d.ts.map +1 -0
  117. package/dist/search/normalize.js +103 -0
  118. package/dist/search/normalize.js.map +1 -0
  119. package/dist/view/allowlist.d.ts +59 -0
  120. package/dist/view/allowlist.d.ts.map +1 -0
  121. package/dist/view/allowlist.js +198 -0
  122. package/dist/view/allowlist.js.map +1 -0
  123. package/dist/view/appearance.d.ts +137 -0
  124. package/dist/view/appearance.d.ts.map +1 -0
  125. package/dist/view/appearance.js +274 -0
  126. package/dist/view/appearance.js.map +1 -0
  127. package/dist/view/css.d.ts +24 -0
  128. package/dist/view/css.d.ts.map +1 -0
  129. package/dist/view/css.js +153 -0
  130. package/dist/view/css.js.map +1 -0
  131. package/dist/view/frame.d.ts +54 -0
  132. package/dist/view/frame.d.ts.map +1 -0
  133. package/dist/view/frame.js +980 -0
  134. package/dist/view/frame.js.map +1 -0
  135. package/dist/view/host.d.ts +160 -0
  136. package/dist/view/host.d.ts.map +1 -0
  137. package/dist/view/host.js +385 -0
  138. package/dist/view/host.js.map +1 -0
  139. package/dist/view/index.d.ts +12 -0
  140. package/dist/view/index.d.ts.map +1 -0
  141. package/dist/view/index.js +7 -0
  142. package/dist/view/index.js.map +1 -0
  143. package/dist/view/protocol.d.ts +220 -0
  144. package/dist/view/protocol.d.ts.map +1 -0
  145. package/dist/view/protocol.js +246 -0
  146. package/dist/view/protocol.js.map +1 -0
  147. package/dist/view/reference.d.ts +18 -0
  148. package/dist/view/reference.d.ts.map +1 -0
  149. package/dist/view/reference.js +25 -0
  150. package/dist/view/reference.js.map +1 -0
  151. package/dist/view/resources.d.ts +51 -0
  152. package/dist/view/resources.d.ts.map +1 -0
  153. package/dist/view/resources.js +242 -0
  154. package/dist/view/resources.js.map +1 -0
  155. package/dist/view/sanitize.d.ts +32 -0
  156. package/dist/view/sanitize.d.ts.map +1 -0
  157. package/dist/view/sanitize.js +226 -0
  158. package/dist/view/sanitize.js.map +1 -0
  159. package/dist/zip/central.d.ts +12 -0
  160. package/dist/zip/central.d.ts.map +1 -0
  161. package/dist/zip/central.js +72 -0
  162. package/dist/zip/central.js.map +1 -0
  163. package/dist/zip/crc32.d.ts +3 -0
  164. package/dist/zip/crc32.d.ts.map +1 -0
  165. package/dist/zip/crc32.js +28 -0
  166. package/dist/zip/crc32.js.map +1 -0
  167. package/dist/zip/eocd.d.ts +9 -0
  168. package/dist/zip/eocd.d.ts.map +1 -0
  169. package/dist/zip/eocd.js +84 -0
  170. package/dist/zip/eocd.js.map +1 -0
  171. package/dist/zip/errors.d.ts +19 -0
  172. package/dist/zip/errors.d.ts.map +1 -0
  173. package/dist/zip/errors.js +37 -0
  174. package/dist/zip/errors.js.map +1 -0
  175. package/dist/zip/index.d.ts +18 -0
  176. package/dist/zip/index.d.ts.map +1 -0
  177. package/dist/zip/index.js +78 -0
  178. package/dist/zip/index.js.map +1 -0
  179. package/dist/zip/inflate.d.ts +2 -0
  180. package/dist/zip/inflate.d.ts.map +1 -0
  181. package/dist/zip/inflate.js +43 -0
  182. package/dist/zip/inflate.js.map +1 -0
  183. package/dist/zip/source.d.ts +15 -0
  184. package/dist/zip/source.d.ts.map +1 -0
  185. package/dist/zip/source.js +34 -0
  186. package/dist/zip/source.js.map +1 -0
  187. package/package.json +75 -0
  188. package/src/core/book.ts +80 -0
  189. package/src/core/errors.ts +31 -0
  190. package/src/core/format.ts +14 -0
  191. package/src/core/graphemes.ts +73 -0
  192. package/src/core/index.ts +27 -0
  193. package/src/core/lookup.ts +16 -0
  194. package/src/core/open.ts +31 -0
  195. package/src/core/position.ts +485 -0
  196. package/src/core/reading-text.ts +200 -0
  197. package/src/core/source.ts +61 -0
  198. package/src/core/storage.ts +6 -0
  199. package/src/core/text.ts +35 -0
  200. package/src/formats/epub/href.ts +54 -0
  201. package/src/formats/epub/index.ts +235 -0
  202. package/src/formats/epub/opf.ts +143 -0
  203. package/src/formats/epub/toc.ts +120 -0
  204. package/src/formats/fb2/index.ts +348 -0
  205. package/src/formats/index.ts +3 -0
  206. package/src/formats/text/index.ts +208 -0
  207. package/src/formats/xml.ts +326 -0
  208. package/src/index.ts +26 -0
  209. package/src/layout/chunk.ts +169 -0
  210. package/src/layout/index.ts +573 -0
  211. package/src/reader/index.ts +1206 -0
  212. package/src/reader/input.ts +122 -0
  213. package/src/search/extract.ts +403 -0
  214. package/src/search/index.ts +10 -0
  215. package/src/search/matcher.ts +187 -0
  216. package/src/search/normalize.ts +122 -0
  217. package/src/view/allowlist.ts +273 -0
  218. package/src/view/appearance.ts +380 -0
  219. package/src/view/css.ts +172 -0
  220. package/src/view/frame.ts +1018 -0
  221. package/src/view/host.ts +527 -0
  222. package/src/view/index.ts +24 -0
  223. package/src/view/protocol.ts +412 -0
  224. package/src/view/reference.ts +30 -0
  225. package/src/view/resources.ts +265 -0
  226. package/src/view/sanitize.ts +266 -0
  227. package/src/zip/central.ts +85 -0
  228. package/src/zip/crc32.ts +30 -0
  229. package/src/zip/eocd.ts +97 -0
  230. package/src/zip/errors.ts +41 -0
  231. package/src/zip/index.ts +114 -0
  232. package/src/zip/inflate.ts +41 -0
  233. package/src/zip/source.ts +51 -0
@@ -0,0 +1,476 @@
1
+ /**
2
+ * The paginator engine: wraps a {@link ContentHost} over a container element and
3
+ * exposes page-oriented navigation, page↔`Position` mapping, and progress on top
4
+ * of the frame's chunked layout. This is the engine the reader facade (M2-4)
5
+ * consumes; it owns no host vocabulary and never fetches or persists.
6
+ *
7
+ * Layout, measurement, chunking, and eviction all live in the frame (Slice 1 —
8
+ * `ContentHost`); this module orchestrates them and bridges page geometry to the
9
+ * headless `Position` model in `src/core`. Core is *called*, never changed: a page
10
+ * maps to a `Position` through `offsetOfPage` → `capturePosition`, and a
11
+ * `Position` maps back through `resolvePosition` → `pageOfOffset`.
12
+ */
13
+ import { capturePosition, resolvePosition } from '../core/index.js';
14
+ import { countGraphemes, graphemeIndexToCodeUnitOffset as graphemeIndexToOffset, segmentGraphemes, } from '../core/graphemes.js';
15
+ import { DEFAULT_CHUNK_CHARS } from './chunk.js';
16
+ import { ContentHost } from '../view/host.js';
17
+ /** How many chunks either side of the active one stay realized (eviction window). */
18
+ const DEFAULT_WINDOW_CHUNKS = 2;
19
+ /** Gap between text columns, in CSS px. */
20
+ const DEFAULT_COLUMN_GAP = 40;
21
+ /** Text columns per page. */
22
+ const DEFAULT_COLUMN_COUNT = 1;
23
+ /** Something went wrong driving the paginator; never a book decoding failure. */
24
+ export class PaginatorError extends Error {
25
+ constructor(message, options) {
26
+ super(message, options);
27
+ this.name = 'PaginatorError';
28
+ }
29
+ }
30
+ /**
31
+ * Drives chunked pagination of one section at a time inside a sandboxed frame.
32
+ *
33
+ * Lifecycle: construct over a container, {@link paginate} a section, navigate
34
+ * with {@link goToPage}/{@link nextPage}/{@link previousPage}, map pages to
35
+ * `Position`s, and {@link destroy} to tear the frame down. A single instance
36
+ * paginates successive sections in turn; re-paginating replaces the active one.
37
+ */
38
+ export class Paginator {
39
+ #host;
40
+ #container;
41
+ #section = null;
42
+ #options = null;
43
+ #state = null;
44
+ #page = 0;
45
+ /** Cached section text, invalidated on each {@link paginate}. */
46
+ #text = null;
47
+ /**
48
+ * Live decoration intent, held for the paginator lifetime so a decoration can be
49
+ * re-anchored and re-drawn after a re-layout (font-size, mode switch, appearance).
50
+ * Draw-only: this is the sole decoration state the engine keeps, and it never
51
+ * leaves memory — nothing is persisted, serialized, or fetched. Keyed by the
52
+ * caller's id; the `className` rides through to the overlay boxes.
53
+ */
54
+ #decorations = new Map();
55
+ constructor(container, options = {}) {
56
+ this.#container = container;
57
+ this.#host = new ContentHost(container, options);
58
+ }
59
+ /** The underlying host, for callers that need the raw frame surface. */
60
+ get host() {
61
+ return this.#host;
62
+ }
63
+ /** The section currently laid out, or `null` before the first {@link paginate}. */
64
+ get section() {
65
+ return this.#section;
66
+ }
67
+ /** The effective options of the current layout, or `null` before {@link paginate}. */
68
+ get options() {
69
+ return this.#options;
70
+ }
71
+ /** The last pagination state, or `null` before {@link paginate}. */
72
+ get state() {
73
+ return this.#state;
74
+ }
75
+ /** The current 0-based page. */
76
+ get page() {
77
+ return this.#page;
78
+ }
79
+ /**
80
+ * Chunks and lays out `section` under `request` (merged with the paginator
81
+ * defaults and the container's measured viewport), resets to page 0, and
82
+ * returns the resulting state. The page count starts as an estimate; call
83
+ * {@link refine} to firm it up. Pass `mode: 'scrolled'` for scrolled layout.
84
+ */
85
+ async paginate(section, request = {}) {
86
+ const options = this.#resolveOptions(request);
87
+ // The text cache is keyed by section: a re-paginate of the same section (a
88
+ // mode switch, an appearance reflow) re-lays out the same text, so the cache
89
+ // survives; a different section invalidates it.
90
+ const sameSection = this.#section === section;
91
+ const state = await this.#host.paginate(section, options);
92
+ this.#section = section;
93
+ this.#options = options;
94
+ this.#state = state;
95
+ this.#page = 0;
96
+ if (!sameSection)
97
+ this.#text = null;
98
+ await this.#redrawDecorations();
99
+ return state;
100
+ }
101
+ /**
102
+ * Re-lays the current section (after a viewport or typography change) and
103
+ * returns the fresh state. The caller preserving position across the relayout
104
+ * should {@link positionOfPage} before and {@link pageOfPosition} after. Text
105
+ * is unchanged, so its cache survives.
106
+ */
107
+ async relayout() {
108
+ this.#requireActive();
109
+ const state = await this.#host.relayout();
110
+ this.#state = state;
111
+ this.#page = clamp(this.#page, 0, Math.max(0, state.pageCount - 1));
112
+ return state;
113
+ }
114
+ /**
115
+ * Re-lays the current section in a different mode, preserving the reading
116
+ * position across the switch: it captures a `Position` for the current page,
117
+ * re-paginates, then seeks back to the page that `Position` now resolves to.
118
+ * Returns the new state. A resolution miss (rare — same text, same session)
119
+ * degrades to page 0.
120
+ */
121
+ async switchMode(mode) {
122
+ this.#requireActive();
123
+ if (this.#options.mode === mode)
124
+ return this.relayout();
125
+ const anchor = await this.positionOfPage(this.#page);
126
+ const state = await this.paginate(this.#section, { ...this.#requestFromOptions(), mode });
127
+ const page = await this.pageOfPosition(anchor);
128
+ if (page >= 0)
129
+ await this.goToPage(page);
130
+ return state;
131
+ }
132
+ /**
133
+ * Re-paginates the current section at the container's *current* size, preserving
134
+ * the reading place. Page geometry is captured once at `paginate` time from the
135
+ * container, so a container that later resizes leaves the frame's content at the
136
+ * old size — it scrolls (shrunk) or leaves a gap (grown); this re-reads the size
137
+ * and re-flows. A no-op (returns `null`) when the size is unchanged or the
138
+ * container is unmeasurable (0×0, e.g. `display:none`), so a `ResizeObserver` may
139
+ * call it on every notification without churn. Mirrors {@link switchMode}: capture
140
+ * a `Position`, re-paginate, seek back (a resolution miss degrades to page 0).
141
+ */
142
+ async resize() {
143
+ this.#requireActive();
144
+ const pageWidth = this.#container.clientWidth;
145
+ const pageHeight = this.#container.clientHeight;
146
+ if (pageWidth === 0 || pageHeight === 0)
147
+ return null;
148
+ if (this.#options.pageWidth === pageWidth && this.#options.pageHeight === pageHeight)
149
+ return null;
150
+ const anchor = await this.positionOfPage(this.#page);
151
+ const state = await this.paginate(this.#section, {
152
+ ...this.#requestFromOptions(),
153
+ pageWidth,
154
+ pageHeight,
155
+ });
156
+ const page = await this.pageOfPosition(anchor);
157
+ if (page >= 0)
158
+ await this.goToPage(page);
159
+ return state;
160
+ }
161
+ /**
162
+ * Drives the estimate toward the true count by re-measuring. In paginated mode
163
+ * the frame refines the count as chunks realize; a `relayout` forces that
164
+ * measurement. Returns the (possibly firm) state. Idempotent once firm.
165
+ */
166
+ async refine() {
167
+ this.#requireActive();
168
+ if (this.#state.firm)
169
+ return this.#state;
170
+ return this.relayout();
171
+ }
172
+ /** Seeks to a 0-based page, clamping to range. Returns the page actually shown. */
173
+ async goToPage(page) {
174
+ this.#requireActive();
175
+ const shown = await this.#host.goToPage(page);
176
+ this.#page = shown;
177
+ return shown;
178
+ }
179
+ /** Turns one page forward, clamped at the last page. Returns the new page. */
180
+ async nextPage() {
181
+ return this.goToPage(this.#page + 1);
182
+ }
183
+ /** Turns one page back, clamped at page 0. Returns the new page. */
184
+ async previousPage() {
185
+ return this.goToPage(this.#page - 1);
186
+ }
187
+ /**
188
+ * The `Position` anchored at the start of `page`: page → character offset via
189
+ * `offsetOfPage`, then `capturePosition(text, offset, sectionId)` over the
190
+ * section text. An empty page (offset -1) captures at offset 0.
191
+ */
192
+ async positionOfPage(page) {
193
+ this.#requireActive();
194
+ const text = await this.#sectionText();
195
+ const offset = await this.#host.offsetOfPage(page);
196
+ return capturePosition(text, Math.max(0, offset), this.#section.id);
197
+ }
198
+ /**
199
+ * The `Position` anchored over a frame-supplied UTF-16 offset range on the
200
+ * section text — the bridge behind selection reporting. The frame computes the
201
+ * range against the same tiled section text this measures against, so the
202
+ * `start` offset is captured directly with `capturePosition` (which takes a
203
+ * UTF-16 offset). The quote spans the whole selection (`start`..`end`), not a
204
+ * fixed default, so a host that highlights the returned Position via `decorate`
205
+ * paints the entire selection rather than only its first ~32 graphemes; resolving
206
+ * it back to a page still keys off the anchor's start.
207
+ */
208
+ async positionOfOffsetRange(start, end) {
209
+ this.#requireActive();
210
+ const text = await this.#sectionText();
211
+ const from = Math.max(0, start);
212
+ const to = Math.max(from, end);
213
+ return capturePosition(text, from, this.#section.id, {
214
+ quoteLength: countGraphemes(text.slice(from, to)),
215
+ });
216
+ }
217
+ /**
218
+ * The 0-based page painting `position`: `resolvePosition` against the section
219
+ * text yields a character offset, then `pageOfOffset` maps it to a page.
220
+ * Returns -1 when the anchor no longer resolves (the caller degrades softly).
221
+ *
222
+ * Note the offset spaces differ: `resolvePosition` returns a *grapheme* index,
223
+ * while `pageOfOffset` speaks UTF-16 code units. They coincide for BMP text and
224
+ * for a text whose graphemes are all single code units; the conversion below
225
+ * maps grapheme index back to a code-unit offset so multi-unit clusters map
226
+ * correctly.
227
+ */
228
+ async pageOfPosition(position) {
229
+ this.#requireActive();
230
+ const text = await this.#sectionText();
231
+ const resolved = resolvePosition(position, text);
232
+ if (resolved === undefined)
233
+ return -1;
234
+ const offset = graphemeIndexToCodeUnitOffset(text, resolved.offset);
235
+ return this.#host.pageOfOffset(offset);
236
+ }
237
+ /**
238
+ * The 0-based page painting the element carrying `elementId`, or -1 when no
239
+ * element in the section carries that id (the caller degrades softly). Bridges
240
+ * fragment anchoring: `offsetOfElementId` in the frame yields the element's
241
+ * character offset, then `pageOfOffset` maps it to a page.
242
+ */
243
+ async pageOfElementId(elementId) {
244
+ this.#requireActive();
245
+ const offset = await this.#host.offsetOfElementId(elementId);
246
+ if (offset < 0)
247
+ return -1;
248
+ return this.#host.pageOfOffset(offset);
249
+ }
250
+ /**
251
+ * Draws a decoration over the range `position` resolves to in the current section,
252
+ * and holds the intent so it survives a re-layout. Draw-only: the paginator keeps
253
+ * only the in-memory intent (id → position + class) and never persists it. The
254
+ * `position` is resolved against the frame-measured section text; its resolved
255
+ * grapheme span is converted to a UTF-16 offset range the frame paints over. A
256
+ * soft-miss — the anchor no longer resolves, or belongs to a section other than the
257
+ * one laid out — draws nothing and throws nothing; the intent is still retained so a
258
+ * later re-layout that brings the anchor back into view redraws it.
259
+ */
260
+ async decorate(decorationId, position, className) {
261
+ this.#requireActive();
262
+ this.#decorations.set(decorationId, { position, className });
263
+ await this.#drawDecoration(decorationId, position, className);
264
+ }
265
+ /** Removes a decoration and drops its intent. A no-op for an unknown id. */
266
+ async undecorate(decorationId) {
267
+ const existed = this.#decorations.delete(decorationId);
268
+ if (this.#section === null)
269
+ return;
270
+ if (existed)
271
+ await this.#host.undecorate(decorationId);
272
+ }
273
+ /**
274
+ * Resolves `position` to a UTF-16 offset range over the section text and sends the
275
+ * frame the draw. A resolution miss (or a `Position` from another section) is a
276
+ * soft-miss: the frame is told to draw nothing (an empty range), never an error.
277
+ */
278
+ async #drawDecoration(decorationId, position, className) {
279
+ const text = await this.#sectionText();
280
+ if (position.sectionId !== this.#section.id) {
281
+ await this.#host.undecorate(decorationId);
282
+ return;
283
+ }
284
+ const resolved = resolvePosition(position, text);
285
+ if (resolved === undefined) {
286
+ await this.#host.undecorate(decorationId);
287
+ return;
288
+ }
289
+ const start = graphemeIndexToCodeUnitOffset(text, resolved.offset);
290
+ const end = graphemeIndexToCodeUnitOffset(text, resolved.offset + resolved.length);
291
+ await this.#host.decorate(decorationId, start, end, className);
292
+ }
293
+ /**
294
+ * Re-resolves and redraws every live decoration against the current section text —
295
+ * the M1-2 re-anchor pipeline, reused for decorations. Called after a re-layout so
296
+ * a highlight tracks the same text through a font-size or mode change. A decoration
297
+ * whose section is not the active one is simply not drawn (its intent is kept).
298
+ */
299
+ async #redrawDecorations() {
300
+ if (this.#decorations.size === 0)
301
+ return;
302
+ for (const [decorationId, { position, className }] of this.#decorations) {
303
+ await this.#drawDecoration(decorationId, position, className);
304
+ }
305
+ }
306
+ /** Within-chapter progress: current page, total (estimate/firm), and fraction. */
307
+ chapterProgress() {
308
+ this.#requireActive();
309
+ const state = this.#state;
310
+ const totalPages = Math.max(1, state.pageCount);
311
+ return {
312
+ mode: this.#options.mode,
313
+ page: this.#page,
314
+ totalPages: state.pageCount,
315
+ firm: state.firm,
316
+ fraction: totalPages <= 1 ? 0 : this.#page / (totalPages - 1),
317
+ realizedChunks: state.realizedChunks,
318
+ totalChunks: state.totalChunks,
319
+ };
320
+ }
321
+ /**
322
+ * Within-book progress. The facade supplies the current section's index and the
323
+ * book's section count; only this section is laid out, so the book fraction is
324
+ * an even-weight approximation across sections and {@link BookProgress.approximate}
325
+ * is always true.
326
+ */
327
+ bookProgress(sectionIndex, sectionCount) {
328
+ const chapter = this.chapterProgress();
329
+ const sections = Math.max(1, sectionCount);
330
+ const bookFraction = clamp((sectionIndex + chapter.fraction) / sections, 0, 1);
331
+ return { ...chapter, sectionIndex, sectionCount, bookFraction, approximate: true };
332
+ }
333
+ /**
334
+ * Applies a new appearance theme stylesheet (see `themeStyleSheet`) to the
335
+ * current section, preserving the reading position across the swap. A theme is
336
+ * colours + background only, so chunk geometry is invariant under it: the same
337
+ * markup re-lays out to the same page count and the captured `Position` resolves
338
+ * back to the exact same page — the reader's place is held, not reset to 0 and
339
+ * not drifted, and the text does not reflow. The theme lives in the srcdoc (not
340
+ * over the wire), so it re-assembles the document; because geometry is invariant
341
+ * the anchor page is restored precisely. Before the first `paginate` it only
342
+ * records the theme for the next render.
343
+ *
344
+ * A no-op when the stylesheet is unchanged, so re-issuing the same appearance is
345
+ * free.
346
+ */
347
+ async setThemeCss(themeCss) {
348
+ if (this.#host.themeCss === themeCss)
349
+ return;
350
+ await this.#reapply(themeCss, this.#options?.columnCount, this.#options?.columnGap);
351
+ }
352
+ /**
353
+ * Applies a live appearance change that may re-flow the layout — a new
354
+ * appearance stylesheet (font/size/line-height/alignment/hyphenation) and/or a
355
+ * new `columnCount` — preserving the reading position across it. Unlike
356
+ * {@link setThemeCss} (colours only, geometry invariant), a reflowing knob
357
+ * changes chunk geometry, so this reuses the same capture → re-layout → resolve →
358
+ * restore machinery as {@link switchMode}: it captures a `Position` for the
359
+ * current page, re-paginates with the new stylesheet and column count, and seeks
360
+ * back to the page that `Position` now resolves to. A same-text resolution miss
361
+ * degrades to page 0. Before the first `paginate` it only records the stylesheet
362
+ * for the next render. A no-op (same stylesheet, same column count) short-
363
+ * circuits, so re-issuing the same appearance is free.
364
+ */
365
+ async applyAppearance(themeCss, geometry = {}) {
366
+ const nextColumns = geometry.columnCount ?? this.#options?.columnCount;
367
+ const nextGap = geometry.columnGap ?? this.#options?.columnGap;
368
+ const sameCss = this.#host.themeCss === themeCss;
369
+ const sameColumns = this.#options === null || this.#options.columnCount === nextColumns;
370
+ const sameGap = this.#options === null || this.#options.columnGap === nextGap;
371
+ if (sameCss && sameColumns && sameGap)
372
+ return;
373
+ await this.#reapply(themeCss, nextColumns, nextGap);
374
+ }
375
+ /**
376
+ * Sets the stylesheet and column geometry, re-paginates the current section, and
377
+ * restores the reading position by content anchor. Shared by {@link setThemeCss}
378
+ * (geometry invariant, exact page restored) and {@link applyAppearance} (geometry
379
+ * may change, nearest anchor page restored). Records the stylesheet and returns
380
+ * before the first `paginate` when no section is laid out yet.
381
+ */
382
+ async #reapply(themeCss, columnCount, columnGap) {
383
+ this.#host.setThemeCss(themeCss);
384
+ if (this.#section === null || this.#options === null)
385
+ return;
386
+ const nextColumns = columnCount ?? this.#options.columnCount;
387
+ const nextGap = columnGap ?? this.#options.columnGap;
388
+ const options = nextColumns === this.#options.columnCount && nextGap === this.#options.columnGap
389
+ ? this.#options
390
+ : { ...this.#options, columnCount: nextColumns, columnGap: nextGap };
391
+ const anchor = await this.positionOfPage(this.#page);
392
+ const state = await this.#host.paginate(this.#section, options);
393
+ this.#options = options;
394
+ this.#state = state;
395
+ // Same section, same text: the section-text cache survives the reflow, so
396
+ // the restore leg below resolves without another sectionText round trip.
397
+ const page = await this.pageOfPosition(anchor);
398
+ await this.goToPage(page >= 0 ? page : 0);
399
+ await this.#redrawDecorations();
400
+ }
401
+ /** Frame-side counts, for eviction/memory checks. Eviction itself lives in-frame. */
402
+ async diagnostics() {
403
+ this.#requireActive();
404
+ return this.#host.diagnostics();
405
+ }
406
+ /** The section's concatenated chunk text, as the frame measures it (cached). */
407
+ async sectionText() {
408
+ this.#requireActive();
409
+ return this.#sectionText();
410
+ }
411
+ /** Tears down the underlying host and frame. Idempotent. */
412
+ destroy() {
413
+ this.#host.destroy();
414
+ this.#section = null;
415
+ this.#options = null;
416
+ this.#state = null;
417
+ this.#text = null;
418
+ this.#decorations.clear();
419
+ }
420
+ async #sectionText() {
421
+ if (this.#text === null)
422
+ this.#text = await this.#host.sectionText();
423
+ return this.#text;
424
+ }
425
+ #resolveOptions(request) {
426
+ return {
427
+ mode: request.mode ?? 'paginated',
428
+ pageWidth: request.pageWidth ?? this.#container.clientWidth,
429
+ pageHeight: request.pageHeight ?? this.#container.clientHeight,
430
+ columnGap: request.columnGap ?? DEFAULT_COLUMN_GAP,
431
+ chunkChars: request.chunkChars ?? DEFAULT_CHUNK_CHARS,
432
+ windowChunks: request.windowChunks ?? DEFAULT_WINDOW_CHUNKS,
433
+ columnCount: request.columnCount ?? DEFAULT_COLUMN_COUNT,
434
+ };
435
+ }
436
+ #requestFromOptions() {
437
+ const options = this.#options;
438
+ return {
439
+ pageWidth: options.pageWidth,
440
+ pageHeight: options.pageHeight,
441
+ columnGap: options.columnGap,
442
+ chunkChars: options.chunkChars,
443
+ windowChunks: options.windowChunks,
444
+ columnCount: options.columnCount,
445
+ };
446
+ }
447
+ #requireActive() {
448
+ if (this.#section === null || this.#options === null || this.#state === null) {
449
+ throw new PaginatorError('no section is paginated; call paginate() first');
450
+ }
451
+ }
452
+ }
453
+ function clamp(value, low, high) {
454
+ return Math.min(high, Math.max(low, value));
455
+ }
456
+ /**
457
+ * Maps a grapheme index (as `resolvePosition` returns) to a UTF-16 code-unit
458
+ * offset (as `pageOfOffset` and `offsetOfPage` speak) in `text`. `Intl.Segmenter`
459
+ * carries each grapheme's code-unit index, so the mapping is exact for surrogate
460
+ * pairs, combining sequences, and emoji clusters. An index at or past the end
461
+ * maps to the text length.
462
+ *
463
+ * The section text is segmented once and memoized (the paginator caches one
464
+ * section text at a time, so a single-entry memo suffices); each lookup is then a
465
+ * binary search over the shared grapheme-boundary helper, never a re-segmentation.
466
+ */
467
+ let memoizedText = null;
468
+ let memoizedGraphemes = [];
469
+ function graphemeIndexToCodeUnitOffset(text, graphemeIndex) {
470
+ if (text !== memoizedText) {
471
+ memoizedText = text;
472
+ memoizedGraphemes = segmentGraphemes(text);
473
+ }
474
+ return graphemeIndexToOffset(memoizedGraphemes, text.length, graphemeIndex);
475
+ }
476
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"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"}