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.
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/core/book.d.ts +75 -0
- package/dist/core/book.d.ts.map +1 -0
- package/dist/core/book.js +2 -0
- package/dist/core/book.js.map +1 -0
- package/dist/core/errors.d.ts +17 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +29 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/format.d.ts +13 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/format.js +2 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/graphemes.d.ts +36 -0
- package/dist/core/graphemes.d.ts.map +1 -0
- package/dist/core/graphemes.js +62 -0
- package/dist/core/graphemes.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lookup.d.ts +10 -0
- package/dist/core/lookup.d.ts.map +1 -0
- package/dist/core/lookup.js +16 -0
- package/dist/core/lookup.js.map +1 -0
- package/dist/core/open.d.ts +12 -0
- package/dist/core/open.d.ts.map +1 -0
- package/dist/core/open.js +23 -0
- package/dist/core/open.js.map +1 -0
- package/dist/core/position.d.ts +121 -0
- package/dist/core/position.d.ts.map +1 -0
- package/dist/core/position.js +327 -0
- package/dist/core/position.js.map +1 -0
- package/dist/core/reading-text.d.ts +77 -0
- package/dist/core/reading-text.d.ts.map +1 -0
- package/dist/core/reading-text.js +144 -0
- package/dist/core/reading-text.js.map +1 -0
- package/dist/core/source.d.ts +17 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +39 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/storage.d.ts +7 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +2 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/text.d.ts +18 -0
- package/dist/core/text.d.ts.map +1 -0
- package/dist/core/text.js +32 -0
- package/dist/core/text.js.map +1 -0
- package/dist/formats/epub/href.d.ts +14 -0
- package/dist/formats/epub/href.d.ts.map +1 -0
- package/dist/formats/epub/href.js +52 -0
- package/dist/formats/epub/href.js.map +1 -0
- package/dist/formats/epub/index.d.ts +3 -0
- package/dist/formats/epub/index.d.ts.map +1 -0
- package/dist/formats/epub/index.js +223 -0
- package/dist/formats/epub/index.js.map +1 -0
- package/dist/formats/epub/opf.d.ts +27 -0
- package/dist/formats/epub/opf.d.ts.map +1 -0
- package/dist/formats/epub/opf.js +110 -0
- package/dist/formats/epub/opf.js.map +1 -0
- package/dist/formats/epub/toc.d.ts +6 -0
- package/dist/formats/epub/toc.d.ts.map +1 -0
- package/dist/formats/epub/toc.js +88 -0
- package/dist/formats/epub/toc.js.map +1 -0
- package/dist/formats/fb2/index.d.ts +13 -0
- package/dist/formats/fb2/index.d.ts.map +1 -0
- package/dist/formats/fb2/index.js +317 -0
- package/dist/formats/fb2/index.js.map +1 -0
- package/dist/formats/index.d.ts +4 -0
- package/dist/formats/index.d.ts.map +1 -0
- package/dist/formats/index.js +4 -0
- package/dist/formats/index.js.map +1 -0
- package/dist/formats/text/index.d.ts +11 -0
- package/dist/formats/text/index.d.ts.map +1 -0
- package/dist/formats/text/index.js +201 -0
- package/dist/formats/text/index.js.map +1 -0
- package/dist/formats/xml.d.ts +33 -0
- package/dist/formats/xml.d.ts.map +1 -0
- package/dist/formats/xml.js +321 -0
- package/dist/formats/xml.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/chunk.d.ts +51 -0
- package/dist/layout/chunk.d.ts.map +1 -0
- package/dist/layout/chunk.js +131 -0
- package/dist/layout/chunk.js.map +1 -0
- package/dist/layout/index.d.ts +238 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +476 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/reader/index.d.ts +231 -0
- package/dist/reader/index.d.ts.map +1 -0
- package/dist/reader/index.js +958 -0
- package/dist/reader/index.js.map +1 -0
- package/dist/reader/input.d.ts +69 -0
- package/dist/reader/input.d.ts.map +1 -0
- package/dist/reader/input.js +75 -0
- package/dist/reader/input.js.map +1 -0
- package/dist/search/extract.d.ts +51 -0
- package/dist/search/extract.d.ts.map +1 -0
- package/dist/search/extract.js +401 -0
- package/dist/search/extract.js.map +1 -0
- package/dist/search/index.d.ts +11 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +11 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/matcher.d.ts +56 -0
- package/dist/search/matcher.d.ts.map +1 -0
- package/dist/search/matcher.js +128 -0
- package/dist/search/matcher.js.map +1 -0
- package/dist/search/normalize.d.ts +48 -0
- package/dist/search/normalize.d.ts.map +1 -0
- package/dist/search/normalize.js +103 -0
- package/dist/search/normalize.js.map +1 -0
- package/dist/view/allowlist.d.ts +59 -0
- package/dist/view/allowlist.d.ts.map +1 -0
- package/dist/view/allowlist.js +198 -0
- package/dist/view/allowlist.js.map +1 -0
- package/dist/view/appearance.d.ts +137 -0
- package/dist/view/appearance.d.ts.map +1 -0
- package/dist/view/appearance.js +274 -0
- package/dist/view/appearance.js.map +1 -0
- package/dist/view/css.d.ts +24 -0
- package/dist/view/css.d.ts.map +1 -0
- package/dist/view/css.js +153 -0
- package/dist/view/css.js.map +1 -0
- package/dist/view/frame.d.ts +54 -0
- package/dist/view/frame.d.ts.map +1 -0
- package/dist/view/frame.js +980 -0
- package/dist/view/frame.js.map +1 -0
- package/dist/view/host.d.ts +160 -0
- package/dist/view/host.d.ts.map +1 -0
- package/dist/view/host.js +385 -0
- package/dist/view/host.js.map +1 -0
- package/dist/view/index.d.ts +12 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +7 -0
- package/dist/view/index.js.map +1 -0
- package/dist/view/protocol.d.ts +220 -0
- package/dist/view/protocol.d.ts.map +1 -0
- package/dist/view/protocol.js +246 -0
- package/dist/view/protocol.js.map +1 -0
- package/dist/view/reference.d.ts +18 -0
- package/dist/view/reference.d.ts.map +1 -0
- package/dist/view/reference.js +25 -0
- package/dist/view/reference.js.map +1 -0
- package/dist/view/resources.d.ts +51 -0
- package/dist/view/resources.d.ts.map +1 -0
- package/dist/view/resources.js +242 -0
- package/dist/view/resources.js.map +1 -0
- package/dist/view/sanitize.d.ts +32 -0
- package/dist/view/sanitize.d.ts.map +1 -0
- package/dist/view/sanitize.js +226 -0
- package/dist/view/sanitize.js.map +1 -0
- package/dist/zip/central.d.ts +12 -0
- package/dist/zip/central.d.ts.map +1 -0
- package/dist/zip/central.js +72 -0
- package/dist/zip/central.js.map +1 -0
- package/dist/zip/crc32.d.ts +3 -0
- package/dist/zip/crc32.d.ts.map +1 -0
- package/dist/zip/crc32.js +28 -0
- package/dist/zip/crc32.js.map +1 -0
- package/dist/zip/eocd.d.ts +9 -0
- package/dist/zip/eocd.d.ts.map +1 -0
- package/dist/zip/eocd.js +84 -0
- package/dist/zip/eocd.js.map +1 -0
- package/dist/zip/errors.d.ts +19 -0
- package/dist/zip/errors.d.ts.map +1 -0
- package/dist/zip/errors.js +37 -0
- package/dist/zip/errors.js.map +1 -0
- package/dist/zip/index.d.ts +18 -0
- package/dist/zip/index.d.ts.map +1 -0
- package/dist/zip/index.js +78 -0
- package/dist/zip/index.js.map +1 -0
- package/dist/zip/inflate.d.ts +2 -0
- package/dist/zip/inflate.d.ts.map +1 -0
- package/dist/zip/inflate.js +43 -0
- package/dist/zip/inflate.js.map +1 -0
- package/dist/zip/source.d.ts +15 -0
- package/dist/zip/source.d.ts.map +1 -0
- package/dist/zip/source.js +34 -0
- package/dist/zip/source.js.map +1 -0
- package/package.json +75 -0
- package/src/core/book.ts +80 -0
- package/src/core/errors.ts +31 -0
- package/src/core/format.ts +14 -0
- package/src/core/graphemes.ts +73 -0
- package/src/core/index.ts +27 -0
- package/src/core/lookup.ts +16 -0
- package/src/core/open.ts +31 -0
- package/src/core/position.ts +485 -0
- package/src/core/reading-text.ts +200 -0
- package/src/core/source.ts +61 -0
- package/src/core/storage.ts +6 -0
- package/src/core/text.ts +35 -0
- package/src/formats/epub/href.ts +54 -0
- package/src/formats/epub/index.ts +235 -0
- package/src/formats/epub/opf.ts +143 -0
- package/src/formats/epub/toc.ts +120 -0
- package/src/formats/fb2/index.ts +348 -0
- package/src/formats/index.ts +3 -0
- package/src/formats/text/index.ts +208 -0
- package/src/formats/xml.ts +326 -0
- package/src/index.ts +26 -0
- package/src/layout/chunk.ts +169 -0
- package/src/layout/index.ts +573 -0
- package/src/reader/index.ts +1206 -0
- package/src/reader/input.ts +122 -0
- package/src/search/extract.ts +403 -0
- package/src/search/index.ts +10 -0
- package/src/search/matcher.ts +187 -0
- package/src/search/normalize.ts +122 -0
- package/src/view/allowlist.ts +273 -0
- package/src/view/appearance.ts +380 -0
- package/src/view/css.ts +172 -0
- package/src/view/frame.ts +1018 -0
- package/src/view/host.ts +527 -0
- package/src/view/index.ts +24 -0
- package/src/view/protocol.ts +412 -0
- package/src/view/reference.ts +30 -0
- package/src/view/resources.ts +265 -0
- package/src/view/sanitize.ts +266 -0
- package/src/zip/central.ts +85 -0
- package/src/zip/crc32.ts +30 -0
- package/src/zip/eocd.ts +97 -0
- package/src/zip/errors.ts +41 -0
- package/src/zip/index.ts +114 -0
- package/src/zip/inflate.ts +41 -0
- package/src/zip/source.ts +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*! wolfy-reader v0.1.0 | @license MIT | (c) Vitaliy Tkachuk | github.com/vitaliy-tkachuk/wolfy-reader */
|
|
2
|
+
/**
|
|
3
|
+
* The package root: the browser-facing reader facade plus the headless core it
|
|
4
|
+
* operates on.
|
|
5
|
+
*
|
|
6
|
+
* import { open, render } from 'wolfy-reader';
|
|
7
|
+
* import { epub } from 'wolfy-reader/epub';
|
|
8
|
+
*
|
|
9
|
+
* Core travels with the facade because `render` takes a `Book` and `open` is the
|
|
10
|
+
* only public way to make one — splitting them would make the common case a
|
|
11
|
+
* three-import dance, and the facade's own surface already names `Position`,
|
|
12
|
+
* `TocItem` and `SentenceRange` in its signatures.
|
|
13
|
+
*
|
|
14
|
+
* Both re-exports resolve to the same emitted modules as `wolfy-reader/core`, so
|
|
15
|
+
* there is one `open`, one `Position` model and one set of error constructors
|
|
16
|
+
* however a consumer reaches them — `instanceof BookError` holds across entries.
|
|
17
|
+
*
|
|
18
|
+
* Headless consumers should import `wolfy-reader/core` instead. This root reaches
|
|
19
|
+
* `src/layout` and `src/view`; it is import-safe under Node today and the pack
|
|
20
|
+
* fidelity check keeps it that way, but only `/core` carries the guarantee.
|
|
21
|
+
*
|
|
22
|
+
* Format decoders are deliberately absent: each is its own subpath because their
|
|
23
|
+
* closures differ by an order of magnitude — only `epub` pulls the ZIP reader —
|
|
24
|
+
* and `open(input, { formats })` takes an explicit list by design.
|
|
25
|
+
*/
|
|
26
|
+
export * from './core/index.js';
|
|
27
|
+
export * from './reader/index.js';
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** The minimal shape the boundary rules read from each top-level node. */
|
|
2
|
+
export interface ChunkNode {
|
|
3
|
+
/** Uppercase tag name for elements, `'#text'` for text nodes. */
|
|
4
|
+
readonly tag: string;
|
|
5
|
+
/** `textContent.length` of this node. */
|
|
6
|
+
readonly chars: number;
|
|
7
|
+
/** Serialized markup — `outerHTML` for elements, escaped text for text nodes. */
|
|
8
|
+
readonly html: string;
|
|
9
|
+
}
|
|
10
|
+
export interface Chunk {
|
|
11
|
+
readonly html: string;
|
|
12
|
+
/** Total characters of text this chunk holds. */
|
|
13
|
+
readonly chars: number;
|
|
14
|
+
/** Number of top-level nodes in this chunk. */
|
|
15
|
+
readonly nodes: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ChunkStats {
|
|
18
|
+
readonly topLevelNodes: number;
|
|
19
|
+
readonly oversizedElements: number;
|
|
20
|
+
readonly largestElementChars: number;
|
|
21
|
+
readonly headingsDeferred: number;
|
|
22
|
+
readonly atomicOversized: number;
|
|
23
|
+
readonly bareTextNodes: number;
|
|
24
|
+
}
|
|
25
|
+
export interface ChunkResult {
|
|
26
|
+
readonly chunks: readonly Chunk[];
|
|
27
|
+
readonly stats: ChunkStats;
|
|
28
|
+
}
|
|
29
|
+
/** Default chunk budget in characters. The whole tradeoff dial; see layout.md. */
|
|
30
|
+
export declare const DEFAULT_CHUNK_CHARS = 8000;
|
|
31
|
+
/**
|
|
32
|
+
* Splits a top-level node list into chunks at flow boundaries, accumulating
|
|
33
|
+
* children until `targetChars` of text is reached.
|
|
34
|
+
*
|
|
35
|
+
* - Split only between top-level (depth-1) children; never descend.
|
|
36
|
+
* - An element larger than the budget is emitted whole as its own chunk (the
|
|
37
|
+
* budget is advisory, not a cap) — descending would put a page break
|
|
38
|
+
* mid-paragraph.
|
|
39
|
+
* - Never end a chunk on a heading or `<hr>`; defer it to the next chunk.
|
|
40
|
+
* - Bare text nodes are glued to the open chunk; whitespace-only ones are
|
|
41
|
+
* dropped by `chunkElement` before this runs.
|
|
42
|
+
*/
|
|
43
|
+
export declare function chunkNodes(nodes: readonly ChunkNode[], targetChars?: number): ChunkResult;
|
|
44
|
+
/**
|
|
45
|
+
* Adapts a live DOM element (a section body) into the `ChunkNode` list the
|
|
46
|
+
* boundary rules read, then chunks it. Whitespace-only bare text nodes are
|
|
47
|
+
* dropped here — they carry no block box and would strand against a formatting
|
|
48
|
+
* context they did not come from.
|
|
49
|
+
*/
|
|
50
|
+
export declare function chunkElement(body: Element, targetChars?: number): ChunkResult;
|
|
51
|
+
//# sourceMappingURL=chunk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../../src/layout/chunk.ts"],"names":[],"mappings":"AAiBA,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAWxC;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,WAAW,SAAsB,GAAG,WAAW,CAmEtG;AAKD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,SAAsB,GAAG,WAAW,CAiB1F"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chunk-boundary rules for the paginator, derived from real EPUB markup (item8
|
|
3
|
+
* of gutenberg-pride-and-prejudice.epub: 571 top-level blocks, 552 `<p>`, max
|
|
4
|
+
* nesting depth 5), not from theory.
|
|
5
|
+
*
|
|
6
|
+
* A chunk boundary becomes a *forced page break*, because each chunk is laid out
|
|
7
|
+
* as its own multi-column formatting context (layout containment forbids a
|
|
8
|
+
* `content-visibility` box fragmenting across columns). So these rules answer
|
|
9
|
+
* "where is a forced page break acceptable", not merely "where is the DOM
|
|
10
|
+
* splittable".
|
|
11
|
+
*
|
|
12
|
+
* The rules run over a structural view of a top-level node list — `ChunkNode` —
|
|
13
|
+
* rather than the DOM directly, so they are pure and unit-testable under
|
|
14
|
+
* `node:test`. `chunkElement` adapts a real DOM element to that view.
|
|
15
|
+
*/
|
|
16
|
+
import { escapeXmlText } from '../core/text.js';
|
|
17
|
+
/** Default chunk budget in characters. The whole tradeoff dial; see layout.md. */
|
|
18
|
+
export const DEFAULT_CHUNK_CHARS = 8000;
|
|
19
|
+
// Splitting *between* these is fine; splitting *inside* one is not — each carries
|
|
20
|
+
// structure (row alignment, list numbering, preformatted whitespace) a second
|
|
21
|
+
// formatting context would restate from scratch.
|
|
22
|
+
const ATOMIC = new Set(['TABLE', 'PRE', 'OL', 'UL', 'DL', 'FIGURE', 'BLOCKQUOTE', 'SVG', 'MATH']);
|
|
23
|
+
// A chunk must never end on one of these: the boundary is a page break, and a
|
|
24
|
+
// heading (or rule) stranded at the foot of a page is the classic orphan.
|
|
25
|
+
const NEVER_LAST = new Set(['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HR']);
|
|
26
|
+
/**
|
|
27
|
+
* Splits a top-level node list into chunks at flow boundaries, accumulating
|
|
28
|
+
* children until `targetChars` of text is reached.
|
|
29
|
+
*
|
|
30
|
+
* - Split only between top-level (depth-1) children; never descend.
|
|
31
|
+
* - An element larger than the budget is emitted whole as its own chunk (the
|
|
32
|
+
* budget is advisory, not a cap) — descending would put a page break
|
|
33
|
+
* mid-paragraph.
|
|
34
|
+
* - Never end a chunk on a heading or `<hr>`; defer it to the next chunk.
|
|
35
|
+
* - Bare text nodes are glued to the open chunk; whitespace-only ones are
|
|
36
|
+
* dropped by `chunkElement` before this runs.
|
|
37
|
+
*/
|
|
38
|
+
export function chunkNodes(nodes, targetChars = DEFAULT_CHUNK_CHARS) {
|
|
39
|
+
let oversizedElements = 0;
|
|
40
|
+
let largestElementChars = 0;
|
|
41
|
+
let headingsDeferred = 0;
|
|
42
|
+
let atomicOversized = 0;
|
|
43
|
+
let bareTextNodes = 0;
|
|
44
|
+
const chunks = [];
|
|
45
|
+
let current = [];
|
|
46
|
+
let currentChars = 0;
|
|
47
|
+
const flush = () => {
|
|
48
|
+
if (current.length === 0)
|
|
49
|
+
return;
|
|
50
|
+
chunks.push({
|
|
51
|
+
html: current.map((node) => node.html).join(''),
|
|
52
|
+
chars: currentChars,
|
|
53
|
+
nodes: current.length,
|
|
54
|
+
});
|
|
55
|
+
current = [];
|
|
56
|
+
currentChars = 0;
|
|
57
|
+
};
|
|
58
|
+
for (const node of nodes) {
|
|
59
|
+
if (node.tag === '#text')
|
|
60
|
+
bareTextNodes += 1;
|
|
61
|
+
if (node.chars > largestElementChars)
|
|
62
|
+
largestElementChars = node.chars;
|
|
63
|
+
if (node.chars >= targetChars) {
|
|
64
|
+
flush();
|
|
65
|
+
oversizedElements += 1;
|
|
66
|
+
if (ATOMIC.has(node.tag))
|
|
67
|
+
atomicOversized += 1;
|
|
68
|
+
current = [node];
|
|
69
|
+
currentChars = node.chars;
|
|
70
|
+
flush();
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (currentChars > 0 && currentChars + node.chars > targetChars) {
|
|
74
|
+
const deferred = [];
|
|
75
|
+
while (current.length > 1 && NEVER_LAST.has(current[current.length - 1].tag)) {
|
|
76
|
+
const moved = current.pop();
|
|
77
|
+
currentChars -= moved.chars;
|
|
78
|
+
deferred.unshift(moved);
|
|
79
|
+
headingsDeferred += 1;
|
|
80
|
+
}
|
|
81
|
+
flush();
|
|
82
|
+
for (const moved of deferred) {
|
|
83
|
+
current.push(moved);
|
|
84
|
+
currentChars += moved.chars;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
current.push(node);
|
|
88
|
+
currentChars += node.chars;
|
|
89
|
+
}
|
|
90
|
+
flush();
|
|
91
|
+
return {
|
|
92
|
+
chunks,
|
|
93
|
+
stats: {
|
|
94
|
+
topLevelNodes: nodes.length,
|
|
95
|
+
oversizedElements,
|
|
96
|
+
largestElementChars,
|
|
97
|
+
headingsDeferred,
|
|
98
|
+
atomicOversized,
|
|
99
|
+
bareTextNodes,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const ELEMENT_NODE = 1;
|
|
104
|
+
const TEXT_NODE = 3;
|
|
105
|
+
/**
|
|
106
|
+
* Adapts a live DOM element (a section body) into the `ChunkNode` list the
|
|
107
|
+
* boundary rules read, then chunks it. Whitespace-only bare text nodes are
|
|
108
|
+
* dropped here — they carry no block box and would strand against a formatting
|
|
109
|
+
* context they did not come from.
|
|
110
|
+
*/
|
|
111
|
+
export function chunkElement(body, targetChars = DEFAULT_CHUNK_CHARS) {
|
|
112
|
+
const nodes = [];
|
|
113
|
+
for (const node of Array.from(body.childNodes)) {
|
|
114
|
+
if (node.nodeType === ELEMENT_NODE) {
|
|
115
|
+
const element = node;
|
|
116
|
+
nodes.push({
|
|
117
|
+
tag: element.tagName.toUpperCase(),
|
|
118
|
+
chars: element.textContent?.length ?? 0,
|
|
119
|
+
html: element.outerHTML,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else if (node.nodeType === TEXT_NODE) {
|
|
123
|
+
const text = node.textContent ?? '';
|
|
124
|
+
if (text.trim().length === 0)
|
|
125
|
+
continue;
|
|
126
|
+
nodes.push({ tag: '#text', chars: text.length, html: escapeXmlText(text) });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return chunkNodes(nodes, targetChars);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=chunk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.js","sourceRoot":"","sources":["../../src/layout/chunk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,238 @@
|
|
|
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 { type Position, type Section } from '../core/index.ts';
|
|
14
|
+
import { ContentHost, type ContentHostOptions } from '../view/host.ts';
|
|
15
|
+
import type { LayoutMode, PaginateOptions, PaginationState } from '../view/protocol.ts';
|
|
16
|
+
export type { LayoutMode, PaginateOptions, PaginationState } from '../view/protocol.ts';
|
|
17
|
+
/**
|
|
18
|
+
* The parts of {@link PaginateOptions} a caller may set without also supplying
|
|
19
|
+
* the viewport geometry, which the paginator measures from its container. Every
|
|
20
|
+
* field is optional; unset fields fall back to the paginator defaults.
|
|
21
|
+
*/
|
|
22
|
+
export interface PaginateRequest {
|
|
23
|
+
readonly mode?: LayoutMode;
|
|
24
|
+
/** Page box width in CSS px. Defaults to the container's client width. */
|
|
25
|
+
readonly pageWidth?: number;
|
|
26
|
+
/** Page box height in CSS px. Defaults to the container's client height. */
|
|
27
|
+
readonly pageHeight?: number;
|
|
28
|
+
readonly columnGap?: number;
|
|
29
|
+
readonly chunkChars?: number;
|
|
30
|
+
readonly windowChunks?: number;
|
|
31
|
+
/** Text columns per page (1 or 2). Defaults to 1. */
|
|
32
|
+
readonly columnCount?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Chapter-local layout state: the current page, the total (estimate or firm),
|
|
36
|
+
* and whether the total has been measured across every chunk yet.
|
|
37
|
+
*/
|
|
38
|
+
export interface ChapterProgress {
|
|
39
|
+
readonly mode: LayoutMode;
|
|
40
|
+
/** 0-based page currently shown. */
|
|
41
|
+
readonly page: number;
|
|
42
|
+
/** Total pages — an estimate until {@link firm}. */
|
|
43
|
+
readonly totalPages: number;
|
|
44
|
+
/** True once every chunk is measured; false while {@link totalPages} churns. */
|
|
45
|
+
readonly firm: boolean;
|
|
46
|
+
/** Fraction through the chapter, 0..1. */
|
|
47
|
+
readonly fraction: number;
|
|
48
|
+
readonly realizedChunks: number;
|
|
49
|
+
readonly totalChunks: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Where the reader is in the whole book. Section counts come from the facade;
|
|
53
|
+
* only the current section is laid out, so any span across other sections is an
|
|
54
|
+
* even-weight approximation — {@link approximate} says so.
|
|
55
|
+
*/
|
|
56
|
+
export interface BookProgress extends ChapterProgress {
|
|
57
|
+
/** 0-based index of the current section in reading order. */
|
|
58
|
+
readonly sectionIndex: number;
|
|
59
|
+
/** Total sections in the book. */
|
|
60
|
+
readonly sectionCount: number;
|
|
61
|
+
/** Fraction through the book, 0..1 — even-weight across sections. */
|
|
62
|
+
readonly bookFraction: number;
|
|
63
|
+
/** Always true: sibling sections are unlaid, so the book span is an estimate. */
|
|
64
|
+
readonly approximate: true;
|
|
65
|
+
}
|
|
66
|
+
export interface PaginatorDiagnostics {
|
|
67
|
+
readonly domNodes: number;
|
|
68
|
+
readonly realizedChunks: number;
|
|
69
|
+
readonly totalChunks: number;
|
|
70
|
+
}
|
|
71
|
+
/** Something went wrong driving the paginator; never a book decoding failure. */
|
|
72
|
+
export declare class PaginatorError extends Error {
|
|
73
|
+
constructor(message: string, options?: ErrorOptions);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Drives chunked pagination of one section at a time inside a sandboxed frame.
|
|
77
|
+
*
|
|
78
|
+
* Lifecycle: construct over a container, {@link paginate} a section, navigate
|
|
79
|
+
* with {@link goToPage}/{@link nextPage}/{@link previousPage}, map pages to
|
|
80
|
+
* `Position`s, and {@link destroy} to tear the frame down. A single instance
|
|
81
|
+
* paginates successive sections in turn; re-paginating replaces the active one.
|
|
82
|
+
*/
|
|
83
|
+
export declare class Paginator {
|
|
84
|
+
#private;
|
|
85
|
+
constructor(container: HTMLElement, options?: ContentHostOptions);
|
|
86
|
+
/** The underlying host, for callers that need the raw frame surface. */
|
|
87
|
+
get host(): ContentHost;
|
|
88
|
+
/** The section currently laid out, or `null` before the first {@link paginate}. */
|
|
89
|
+
get section(): Section | null;
|
|
90
|
+
/** The effective options of the current layout, or `null` before {@link paginate}. */
|
|
91
|
+
get options(): PaginateOptions | null;
|
|
92
|
+
/** The last pagination state, or `null` before {@link paginate}. */
|
|
93
|
+
get state(): PaginationState | null;
|
|
94
|
+
/** The current 0-based page. */
|
|
95
|
+
get page(): number;
|
|
96
|
+
/**
|
|
97
|
+
* Chunks and lays out `section` under `request` (merged with the paginator
|
|
98
|
+
* defaults and the container's measured viewport), resets to page 0, and
|
|
99
|
+
* returns the resulting state. The page count starts as an estimate; call
|
|
100
|
+
* {@link refine} to firm it up. Pass `mode: 'scrolled'` for scrolled layout.
|
|
101
|
+
*/
|
|
102
|
+
paginate(section: Section, request?: PaginateRequest): Promise<PaginationState>;
|
|
103
|
+
/**
|
|
104
|
+
* Re-lays the current section (after a viewport or typography change) and
|
|
105
|
+
* returns the fresh state. The caller preserving position across the relayout
|
|
106
|
+
* should {@link positionOfPage} before and {@link pageOfPosition} after. Text
|
|
107
|
+
* is unchanged, so its cache survives.
|
|
108
|
+
*/
|
|
109
|
+
relayout(): Promise<PaginationState>;
|
|
110
|
+
/**
|
|
111
|
+
* Re-lays the current section in a different mode, preserving the reading
|
|
112
|
+
* position across the switch: it captures a `Position` for the current page,
|
|
113
|
+
* re-paginates, then seeks back to the page that `Position` now resolves to.
|
|
114
|
+
* Returns the new state. A resolution miss (rare — same text, same session)
|
|
115
|
+
* degrades to page 0.
|
|
116
|
+
*/
|
|
117
|
+
switchMode(mode: LayoutMode): Promise<PaginationState>;
|
|
118
|
+
/**
|
|
119
|
+
* Re-paginates the current section at the container's *current* size, preserving
|
|
120
|
+
* the reading place. Page geometry is captured once at `paginate` time from the
|
|
121
|
+
* container, so a container that later resizes leaves the frame's content at the
|
|
122
|
+
* old size — it scrolls (shrunk) or leaves a gap (grown); this re-reads the size
|
|
123
|
+
* and re-flows. A no-op (returns `null`) when the size is unchanged or the
|
|
124
|
+
* container is unmeasurable (0×0, e.g. `display:none`), so a `ResizeObserver` may
|
|
125
|
+
* call it on every notification without churn. Mirrors {@link switchMode}: capture
|
|
126
|
+
* a `Position`, re-paginate, seek back (a resolution miss degrades to page 0).
|
|
127
|
+
*/
|
|
128
|
+
resize(): Promise<PaginationState | null>;
|
|
129
|
+
/**
|
|
130
|
+
* Drives the estimate toward the true count by re-measuring. In paginated mode
|
|
131
|
+
* the frame refines the count as chunks realize; a `relayout` forces that
|
|
132
|
+
* measurement. Returns the (possibly firm) state. Idempotent once firm.
|
|
133
|
+
*/
|
|
134
|
+
refine(): Promise<PaginationState>;
|
|
135
|
+
/** Seeks to a 0-based page, clamping to range. Returns the page actually shown. */
|
|
136
|
+
goToPage(page: number): Promise<number>;
|
|
137
|
+
/** Turns one page forward, clamped at the last page. Returns the new page. */
|
|
138
|
+
nextPage(): Promise<number>;
|
|
139
|
+
/** Turns one page back, clamped at page 0. Returns the new page. */
|
|
140
|
+
previousPage(): Promise<number>;
|
|
141
|
+
/**
|
|
142
|
+
* The `Position` anchored at the start of `page`: page → character offset via
|
|
143
|
+
* `offsetOfPage`, then `capturePosition(text, offset, sectionId)` over the
|
|
144
|
+
* section text. An empty page (offset -1) captures at offset 0.
|
|
145
|
+
*/
|
|
146
|
+
positionOfPage(page: number): Promise<Position>;
|
|
147
|
+
/**
|
|
148
|
+
* The `Position` anchored over a frame-supplied UTF-16 offset range on the
|
|
149
|
+
* section text — the bridge behind selection reporting. The frame computes the
|
|
150
|
+
* range against the same tiled section text this measures against, so the
|
|
151
|
+
* `start` offset is captured directly with `capturePosition` (which takes a
|
|
152
|
+
* UTF-16 offset). The quote spans the whole selection (`start`..`end`), not a
|
|
153
|
+
* fixed default, so a host that highlights the returned Position via `decorate`
|
|
154
|
+
* paints the entire selection rather than only its first ~32 graphemes; resolving
|
|
155
|
+
* it back to a page still keys off the anchor's start.
|
|
156
|
+
*/
|
|
157
|
+
positionOfOffsetRange(start: number, end: number): Promise<Position>;
|
|
158
|
+
/**
|
|
159
|
+
* The 0-based page painting `position`: `resolvePosition` against the section
|
|
160
|
+
* text yields a character offset, then `pageOfOffset` maps it to a page.
|
|
161
|
+
* Returns -1 when the anchor no longer resolves (the caller degrades softly).
|
|
162
|
+
*
|
|
163
|
+
* Note the offset spaces differ: `resolvePosition` returns a *grapheme* index,
|
|
164
|
+
* while `pageOfOffset` speaks UTF-16 code units. They coincide for BMP text and
|
|
165
|
+
* for a text whose graphemes are all single code units; the conversion below
|
|
166
|
+
* maps grapheme index back to a code-unit offset so multi-unit clusters map
|
|
167
|
+
* correctly.
|
|
168
|
+
*/
|
|
169
|
+
pageOfPosition(position: Position): Promise<number>;
|
|
170
|
+
/**
|
|
171
|
+
* The 0-based page painting the element carrying `elementId`, or -1 when no
|
|
172
|
+
* element in the section carries that id (the caller degrades softly). Bridges
|
|
173
|
+
* fragment anchoring: `offsetOfElementId` in the frame yields the element's
|
|
174
|
+
* character offset, then `pageOfOffset` maps it to a page.
|
|
175
|
+
*/
|
|
176
|
+
pageOfElementId(elementId: string): Promise<number>;
|
|
177
|
+
/**
|
|
178
|
+
* Draws a decoration over the range `position` resolves to in the current section,
|
|
179
|
+
* and holds the intent so it survives a re-layout. Draw-only: the paginator keeps
|
|
180
|
+
* only the in-memory intent (id → position + class) and never persists it. The
|
|
181
|
+
* `position` is resolved against the frame-measured section text; its resolved
|
|
182
|
+
* grapheme span is converted to a UTF-16 offset range the frame paints over. A
|
|
183
|
+
* soft-miss — the anchor no longer resolves, or belongs to a section other than the
|
|
184
|
+
* one laid out — draws nothing and throws nothing; the intent is still retained so a
|
|
185
|
+
* later re-layout that brings the anchor back into view redraws it.
|
|
186
|
+
*/
|
|
187
|
+
decorate(decorationId: string, position: Position, className: string): Promise<void>;
|
|
188
|
+
/** Removes a decoration and drops its intent. A no-op for an unknown id. */
|
|
189
|
+
undecorate(decorationId: string): Promise<void>;
|
|
190
|
+
/** Within-chapter progress: current page, total (estimate/firm), and fraction. */
|
|
191
|
+
chapterProgress(): ChapterProgress;
|
|
192
|
+
/**
|
|
193
|
+
* Within-book progress. The facade supplies the current section's index and the
|
|
194
|
+
* book's section count; only this section is laid out, so the book fraction is
|
|
195
|
+
* an even-weight approximation across sections and {@link BookProgress.approximate}
|
|
196
|
+
* is always true.
|
|
197
|
+
*/
|
|
198
|
+
bookProgress(sectionIndex: number, sectionCount: number): BookProgress;
|
|
199
|
+
/**
|
|
200
|
+
* Applies a new appearance theme stylesheet (see `themeStyleSheet`) to the
|
|
201
|
+
* current section, preserving the reading position across the swap. A theme is
|
|
202
|
+
* colours + background only, so chunk geometry is invariant under it: the same
|
|
203
|
+
* markup re-lays out to the same page count and the captured `Position` resolves
|
|
204
|
+
* back to the exact same page — the reader's place is held, not reset to 0 and
|
|
205
|
+
* not drifted, and the text does not reflow. The theme lives in the srcdoc (not
|
|
206
|
+
* over the wire), so it re-assembles the document; because geometry is invariant
|
|
207
|
+
* the anchor page is restored precisely. Before the first `paginate` it only
|
|
208
|
+
* records the theme for the next render.
|
|
209
|
+
*
|
|
210
|
+
* A no-op when the stylesheet is unchanged, so re-issuing the same appearance is
|
|
211
|
+
* free.
|
|
212
|
+
*/
|
|
213
|
+
setThemeCss(themeCss: string | undefined): Promise<void>;
|
|
214
|
+
/**
|
|
215
|
+
* Applies a live appearance change that may re-flow the layout — a new
|
|
216
|
+
* appearance stylesheet (font/size/line-height/alignment/hyphenation) and/or a
|
|
217
|
+
* new `columnCount` — preserving the reading position across it. Unlike
|
|
218
|
+
* {@link setThemeCss} (colours only, geometry invariant), a reflowing knob
|
|
219
|
+
* changes chunk geometry, so this reuses the same capture → re-layout → resolve →
|
|
220
|
+
* restore machinery as {@link switchMode}: it captures a `Position` for the
|
|
221
|
+
* current page, re-paginates with the new stylesheet and column count, and seeks
|
|
222
|
+
* back to the page that `Position` now resolves to. A same-text resolution miss
|
|
223
|
+
* degrades to page 0. Before the first `paginate` it only records the stylesheet
|
|
224
|
+
* for the next render. A no-op (same stylesheet, same column count) short-
|
|
225
|
+
* circuits, so re-issuing the same appearance is free.
|
|
226
|
+
*/
|
|
227
|
+
applyAppearance(themeCss: string | undefined, geometry?: {
|
|
228
|
+
columnCount?: number;
|
|
229
|
+
columnGap?: number;
|
|
230
|
+
}): Promise<void>;
|
|
231
|
+
/** Frame-side counts, for eviction/memory checks. Eviction itself lives in-frame. */
|
|
232
|
+
diagnostics(): Promise<PaginatorDiagnostics>;
|
|
233
|
+
/** The section's concatenated chunk text, as the frame measures it (cached). */
|
|
234
|
+
sectionText(): Promise<string>;
|
|
235
|
+
/** Tears down the underlying host and frame. Idempotent. */
|
|
236
|
+
destroy(): void;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAoC,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQjG,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAExF,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AASxF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,kCAAkC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,iFAAiF;AACjF,qBAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED;;;;;;;GAOG;AACH,qBAAa,SAAS;;IAkBpB,YAAY,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,EAGnE;IAED,wEAAwE;IACxE,IAAI,IAAI,IAAI,WAAW,CAEtB;IAED,mFAAmF;IACnF,IAAI,OAAO,IAAI,OAAO,GAAG,IAAI,CAE5B;IAED,sFAAsF;IACtF,IAAI,OAAO,IAAI,eAAe,GAAG,IAAI,CAEpC;IAED,oEAAoE;IACpE,IAAI,KAAK,IAAI,eAAe,GAAG,IAAI,CAElC;IAED,gCAAgC;IAChC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAcxF;IAED;;;;;OAKG;IACG,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAMzC;IAED;;;;;;OAMG;IACG,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CAQ3D;IAED;;;;;;;;;OASG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAe9C;IAED;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAIvC;IAED,mFAAmF;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK5C;IAED,8EAA8E;IACxE,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhC;IAED,oEAAoE;IAC9D,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpC;IAED;;;;OAIG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAKpD;IAED;;;;;;;;;OASG;IACG,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQzE;IAED;;;;;;;;;;OAUG;IACG,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxD;IAED;;;;;OAKG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKxD;IAED;;;;;;;;;OASG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzF;IAED,4EAA4E;IACtE,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpD;IAoCD,kFAAkF;IAClF,eAAe,IAAI,eAAe,CAajC;IAED;;;;;OAKG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,CAKrE;IAED;;;;;;;;;;;;;OAaG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7D;IAED;;;;;;;;;;;;OAYG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1D,OAAO,CAAC,IAAI,CAAC,CAQf;IAiCD,qFAAqF;IAC/E,WAAW,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAGjD;IAED,gFAAgF;IAC1E,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnC;IAED,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAOd;CAoCF"}
|