@shadow-garden/bapbong-view 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.
@@ -0,0 +1,147 @@
1
+ import { Node as ProseMirrorNode, Schema } from 'prosemirror-model';
2
+ import type { CaretRect, MeasureMetrics, MeasureText, PagePoint, RangeDecoration, ResolvedLayout, SelectionRect } from '@shadow-garden/bapbong-contracts';
3
+ export interface RenderCoreOptions {
4
+ /** The scroll viewport the page stack lives in (used for virtualization and
5
+ * scroll-into-view). Defaults to `stack.closest('.canvas-wrap')`. */
6
+ viewport?: HTMLElement;
7
+ /** Initial zoom factor (1 = 100%). */
8
+ zoom?: number;
9
+ /** Build a visually-hidden ARIA mirror of the document for screen readers
10
+ * (the canvas is opaque to assistive tech). Default true; pass false to opt
11
+ * out. `a11yLabel` sets its `aria-label`. */
12
+ a11y?: boolean;
13
+ a11yLabel?: string;
14
+ /** Text-width measurer. Defaults to a canvas-backed one (browser). Inject an
15
+ * engine-independent measurer (e.g. font-file metrics) to make wrapping and
16
+ * pagination deterministic across WebView engines / headless. */
17
+ measureText?: MeasureText;
18
+ /** Vertical-metrics provider, paired with {@link measureText}. Defaults to a
19
+ * canvas-backed one. */
20
+ measureMetrics?: MeasureMetrics;
21
+ }
22
+ /** Caret + selection to paint on the overlay layer (page-local geometry). */
23
+ export interface Overlay {
24
+ caret?: CaretRect | null;
25
+ selection?: SelectionRect[];
26
+ }
27
+ /**
28
+ * The render half of bapbong, with **no editing**: import → layout → paint →
29
+ * scroll/zoom/virtualize, plus the geometry queries (`caretRect`, `hitTest`,
30
+ * `pageToCanvas`, …) the editor and viewer both need.
31
+ *
32
+ * It holds a **read-only ProseMirror doc** (a `Node`, not an `EditorState`) and
33
+ * knows nothing about the input-bridge / editing. The {@link BapbongView}
34
+ * viewer uses it directly; `BapbongEditor` composes it and feeds it a fresh doc
35
+ * (plus a caret/selection overlay) on every transaction — so layout/paint live
36
+ * in exactly one place.
37
+ */
38
+ export declare class RenderCore {
39
+ readonly stack: HTMLElement;
40
+ private readonly viewport;
41
+ private readonly painter;
42
+ private readonly measureText;
43
+ private readonly measureMetrics;
44
+ private resolved;
45
+ private doc;
46
+ private zoomFactor;
47
+ private chromeHeaders;
48
+ private chromeFooters;
49
+ private chromeTitlePg;
50
+ private chromeEvenAndOdd;
51
+ private footnotes;
52
+ private importedRaw;
53
+ private docSchema;
54
+ private page;
55
+ private layoutCache;
56
+ private lastOverlay;
57
+ private decorationProvider;
58
+ private scrollRaf;
59
+ private docFamilies;
60
+ private fontRelayoutTimer;
61
+ private readonly fontsListeners;
62
+ private readonly a11y;
63
+ constructor(stack: HTMLElement, opts?: RenderCoreOptions);
64
+ /** The current read-only document, or null before the first load. */
65
+ get document(): ProseMirrorNode | null;
66
+ /** The resolved layout for the current doc, or null. */
67
+ get layout(): ResolvedLayout | null;
68
+ /** Number of laid-out pages (0 before the first document). */
69
+ get pageCount(): number;
70
+ /** The document schema in use (model's base, or a caller-supplied extension). */
71
+ get schema(): Schema;
72
+ /** Resolve doc-range decorations to page rects on each content paint. */
73
+ setDecorationProvider(fn: (() => RangeDecoration[]) | null): void;
74
+ /**
75
+ * Import a `.docx`, lay it out, and (by default) paint the first frame. Pass
76
+ * `{ schema }` to import against an extended schema (e.g. plugin marks);
77
+ * `{ paint: false }` to skip the initial paint (the editor paints with a caret
78
+ * overlay itself). Resolves with the doc + imported page-chrome keys.
79
+ */
80
+ loadDocx(bytes: ArrayBuffer, opts?: {
81
+ schema?: Schema;
82
+ paint?: boolean;
83
+ }): Promise<{
84
+ doc: ProseMirrorNode;
85
+ headerKeys: string[];
86
+ footerKeys: string[];
87
+ }>;
88
+ /** Export the current document to .docx bytes, carrying the imported source
89
+ * package so unmodelled parts survive the round-trip. */
90
+ exportDocx(): Promise<Uint8Array>;
91
+ /** Lay out (or re-lay, incrementally) `doc` and store it. Does not paint. */
92
+ layoutDoc(doc: ProseMirrorNode): void;
93
+ /** Full content repaint, virtualized to the scroll viewport. Pass an overlay
94
+ * to update the caret/selection painted on top (kept for later repaints). */
95
+ paintContent(overlay?: Overlay): void;
96
+ /** Redraw only the caret/selection overlay (just the affected page canvases —
97
+ * used for caret blink, drag preview, selection-only changes). */
98
+ paintOverlay(overlay: Overlay): void;
99
+ /** Set the zoom factor (1 = 100%) and repaint content at the new scale. */
100
+ setZoom(zoom: number): void;
101
+ /** The current zoom factor. */
102
+ getZoom(): number;
103
+ /**
104
+ * Print the whole document. The live canvas is virtualized (only visible
105
+ * pages exist), so this renders **every** page with a throwaway painter,
106
+ * snapshots each to a PNG, and prints one image per sheet via a hidden iframe
107
+ * (clean pagination, the live view untouched).
108
+ */
109
+ print(): Promise<void>;
110
+ /** Gather decorations from the provider and resolve each doc range to
111
+ * page-local rects the painter can fill directly. */
112
+ private collectDecorations;
113
+ /** Caret geometry at a doc position (page-local), or null. */
114
+ caretRect(pos: number): CaretRect | null;
115
+ /** Selection highlight rects for a doc range (page-local). */
116
+ selectionRects(from: number, to: number): SelectionRect[];
117
+ /** The doc position one line above/below `head` at horizontal `x`, or null. */
118
+ verticalCaret(head: number, dir: -1 | 1, x: number): number | null;
119
+ /** Map client (viewport) coords to a page-local point, or null. */
120
+ clientToPage(clientX: number, clientY: number): PagePoint | null;
121
+ /** The doc position under a page-local point, or null. */
122
+ posAtPoint(point: PagePoint): number | null;
123
+ /** The doc position under a pointer/mouse event, or null. */
124
+ posAtEvent(ev: {
125
+ clientX: number;
126
+ clientY: number;
127
+ }): number | null;
128
+ /** Map a page-local point to container (canvas-stack) coordinates, or null. */
129
+ pageToCanvas(p: PagePoint): {
130
+ x: number;
131
+ y: number;
132
+ } | null;
133
+ /** Scroll the viewport so the caret at `pos` sits `topMargin` px from the top. */
134
+ scrollToPos(pos: number, topMargin?: number): void;
135
+ /** The viewport's window onto the page stack, in container CSS px. */
136
+ private currentViewport;
137
+ /** Subscribe to late-font relayouts (page geometry changed → recompute any
138
+ * caret/selection rects you hold). Returns an unsubscribe fn. */
139
+ onFontsReloaded(cb: () => void): () => void;
140
+ destroy(): void;
141
+ /** Repaint newly visible pages while scrolling (rAF-throttled). */
142
+ private onScroll;
143
+ private onFontsLoaded;
144
+ }
145
+ /** Every fontFamily mark in the given documents, plus the engine default. */
146
+ export declare function collectFontFamilies(...docs: (ProseMirrorNode | undefined)[]): string[];
147
+ //# sourceMappingURL=render-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-core.d.ts","sourceRoot":"","sources":["../../src/lib/render-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { RenderCore } from './render-core.js';
2
+ /**
3
+ * Read-only text selection for {@link BapbongView}. A canvas paints text as
4
+ * pixels — there is nothing to drag-select — so this mirrors the editor's
5
+ * approach: hit-test the pointer to document positions, paint the selection
6
+ * rects on the canvas overlay (same geometry the painter uses, so it aligns
7
+ * exactly at any zoom), and copy the selected text from the document model.
8
+ *
9
+ * No input-bridge / ProseMirror editing is involved — it only reads the doc and
10
+ * the layout the {@link RenderCore} already holds. (The sr-only ARIA mirror is a
11
+ * separate concern: it serves screen readers, not mouse selection.)
12
+ */
13
+ export declare class ViewerSelection {
14
+ private readonly core;
15
+ private anchor;
16
+ private head;
17
+ private dragging;
18
+ constructor(core: RenderCore);
19
+ /** Drop any current selection (e.g. when a new document loads). */
20
+ clear(): void;
21
+ destroy(): void;
22
+ private onDown;
23
+ private onMove;
24
+ private onUp;
25
+ /** Double-click selects the word under the pointer. */
26
+ private onDblClick;
27
+ private onKey;
28
+ private range;
29
+ private paint;
30
+ private selectedText;
31
+ }
32
+ //# sourceMappingURL=viewer-selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewer-selection.d.ts","sourceRoot":"","sources":["../../src/lib/viewer-selection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAKd,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,QAAQ,CAAS;gBAEI,IAAI,EAAE,UAAU;IAc7C,mEAAmE;IACnE,KAAK,IAAI,IAAI;IAMb,OAAO,IAAI,IAAI;IAYf,OAAO,CAAC,MAAM,CAcZ;IAEF,OAAO,CAAC,MAAM,CAQZ;IAEF,OAAO,CAAC,IAAI,CAEV;IAEF,uDAAuD;IACvD,OAAO,CAAC,UAAU,CAUhB;IAIF,OAAO,CAAC,KAAK,CAmBX;IAIF,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,YAAY;CAMrB"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@shadow-garden/bapbong-view",
3
+ "version": "0.1.0",
4
+ "description": "bapbong — render core + read-only viewer (preview). Loads/lays-out/paints a .docx to canvas with zoom + page virtualization, no input-bridge (no ProseMirror editing).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/shadowgarden-app/bapbong.git",
9
+ "directory": "packages/view"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/index.cjs",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ "./package.json": "./package.json",
17
+ ".": {
18
+ "@shadow-garden/source": "./src/index.ts",
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "!**/*.tsbuildinfo"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "nx": {
33
+ "tags": [
34
+ "scope:view"
35
+ ],
36
+ "targets": {
37
+ "build": {
38
+ "executor": "@nx/esbuild:esbuild",
39
+ "outputs": [
40
+ "{options.outputPath}"
41
+ ],
42
+ "options": {
43
+ "outputPath": "packages/view/dist",
44
+ "main": "packages/view/src/index.ts",
45
+ "tsConfig": "packages/view/tsconfig.lib.json",
46
+ "format": [
47
+ "esm",
48
+ "cjs"
49
+ ],
50
+ "declarationRootDir": "packages/view/src",
51
+ "external": [
52
+ "@shadow-garden/bapbong-contracts",
53
+ "@shadow-garden/bapbong-model",
54
+ "@shadow-garden/bapbong-docx",
55
+ "@shadow-garden/bapbong-measuring",
56
+ "@shadow-garden/bapbong-layout-engine",
57
+ "@shadow-garden/bapbong-painter-canvas",
58
+ "@shadow-garden/bapbong-selection",
59
+ "@shadow-garden/bapbong-a11y"
60
+ ]
61
+ }
62
+ }
63
+ }
64
+ },
65
+ "dependencies": {
66
+ "prosemirror-model": "^1.25.7",
67
+ "@shadow-garden/bapbong-contracts": "^0.1.0",
68
+ "@shadow-garden/bapbong-model": "^0.1.0",
69
+ "@shadow-garden/bapbong-docx": "^0.1.0",
70
+ "@shadow-garden/bapbong-measuring": "^0.1.0",
71
+ "@shadow-garden/bapbong-layout-engine": "^0.1.0",
72
+ "@shadow-garden/bapbong-painter-canvas": "^0.1.0",
73
+ "@shadow-garden/bapbong-selection": "^0.1.0",
74
+ "@shadow-garden/bapbong-a11y": "^0.1.0"
75
+ }
76
+ }