@rtif-sdk/web 1.1.0 → 1.4.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 (52) hide show
  1. package/dist/block-drag-handler.js +4 -1
  2. package/dist/block-drag-handler.js.map +1 -1
  3. package/dist/content-handler-html.d.ts +28 -0
  4. package/dist/content-handler-html.d.ts.map +1 -0
  5. package/dist/content-handler-html.js +49 -0
  6. package/dist/content-handler-html.js.map +1 -0
  7. package/dist/content-handlers.d.ts +20 -19
  8. package/dist/content-handlers.d.ts.map +1 -1
  9. package/dist/content-handlers.js +4 -43
  10. package/dist/content-handlers.js.map +1 -1
  11. package/dist/editor.d.ts.map +1 -1
  12. package/dist/editor.js +119 -5
  13. package/dist/editor.js.map +1 -1
  14. package/dist/index.d.ts +12 -4
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +15 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/preset-basic.d.ts +20 -0
  19. package/dist/preset-basic.d.ts.map +1 -0
  20. package/dist/preset-basic.js +28 -0
  21. package/dist/preset-basic.js.map +1 -0
  22. package/dist/preset-full.d.ts +22 -0
  23. package/dist/preset-full.d.ts.map +1 -0
  24. package/dist/preset-full.js +66 -0
  25. package/dist/preset-full.js.map +1 -0
  26. package/dist/preset-plaintext.d.ts +20 -0
  27. package/dist/preset-plaintext.d.ts.map +1 -0
  28. package/dist/preset-plaintext.js +19 -0
  29. package/dist/preset-plaintext.js.map +1 -0
  30. package/dist/preset-standard.d.ts +22 -0
  31. package/dist/preset-standard.d.ts.map +1 -0
  32. package/dist/preset-standard.js +47 -0
  33. package/dist/preset-standard.js.map +1 -0
  34. package/dist/presets.d.ts +7 -88
  35. package/dist/presets.d.ts.map +1 -1
  36. package/dist/presets.js +7 -152
  37. package/dist/presets.js.map +1 -1
  38. package/dist/renderer.d.ts +29 -0
  39. package/dist/renderer.d.ts.map +1 -1
  40. package/dist/renderer.js +107 -77
  41. package/dist/renderer.js.map +1 -1
  42. package/dist/spatial-index.d.ts +203 -0
  43. package/dist/spatial-index.d.ts.map +1 -0
  44. package/dist/spatial-index.js +211 -0
  45. package/dist/spatial-index.js.map +1 -0
  46. package/dist/types.d.ts +82 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/virtual-viewport.d.ts +241 -0
  49. package/dist/virtual-viewport.d.ts.map +1 -0
  50. package/dist/virtual-viewport.js +584 -0
  51. package/dist/virtual-viewport.js.map +1 -0
  52. package/package.json +1 -1
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Virtual viewport for block-level DOM virtualization.
3
+ *
4
+ * Manages which blocks are rendered into the DOM based on scroll position,
5
+ * using spacer elements to maintain correct scroll height. Only blocks
6
+ * within the visible range (plus a configurable buffer) are present in the
7
+ * DOM at any time, enabling smooth editing of documents with thousands of
8
+ * blocks.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { Document } from '@rtif-sdk/core';
13
+ import type { SpatialIndex } from './spatial-index.js';
14
+ import type { MarkRendererRegistry } from './mark-renderer.js';
15
+ import type { BlockRendererRegistry } from './block-renderer.js';
16
+ /**
17
+ * Configuration for creating a {@link VirtualViewport}.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const config: VirtualViewportConfig = {
22
+ * root: document.getElementById('editor')!,
23
+ * bufferSize: 15,
24
+ * estimatedBlockHeight: 28,
25
+ * };
26
+ * ```
27
+ */
28
+ export interface VirtualViewportConfig {
29
+ /** The root contenteditable element that contains block elements. */
30
+ readonly root: HTMLElement;
31
+ /**
32
+ * Number of extra blocks to render above and below the visible range
33
+ * for smoother scrolling. Higher values reduce flashing at the cost
34
+ * of more DOM nodes.
35
+ *
36
+ * Default: `10`.
37
+ */
38
+ readonly bufferSize?: number;
39
+ /**
40
+ * Default estimated pixel height for block types not listed in
41
+ * {@link blockTypeHeights}. Passed through to the spatial index.
42
+ *
43
+ * Default: `24`.
44
+ */
45
+ readonly estimatedBlockHeight?: number;
46
+ /**
47
+ * Estimated pixel heights per block type string.
48
+ * Passed through to the spatial index config.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * { heading: 48, image: 250 }
53
+ * ```
54
+ */
55
+ readonly blockTypeHeights?: Record<string, number>;
56
+ /**
57
+ * The scrollable ancestor element, or `window`. When omitted, the
58
+ * viewport walks DOM ancestors to auto-detect the nearest scrollable
59
+ * container via {@link findScrollParent}.
60
+ */
61
+ readonly scrollContainer?: HTMLElement | Window;
62
+ }
63
+ /**
64
+ * A virtual viewport that keeps only visible blocks in the DOM.
65
+ *
66
+ * Create with {@link createVirtualViewport}. The viewport manages spacer
67
+ * elements, scroll listeners, and height measurement to provide seamless
68
+ * editing of large documents.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const vp = createVirtualViewport({ root }, doc);
73
+ * vp.renderInitial(doc, markRenderers, blockRenderers, blockElementMap);
74
+ * // On scroll, the viewport automatically updates visible blocks.
75
+ * // On document change:
76
+ * vp.reconcile(prevDoc, nextDoc, composingBlockId, markRenderers, blockRenderers, blockElementMap);
77
+ * ```
78
+ */
79
+ export interface VirtualViewport {
80
+ /** The spatial index used for layout calculations. */
81
+ readonly spatialIndex: SpatialIndex;
82
+ /** The currently rendered block index range (start inclusive, end exclusive). */
83
+ readonly renderedRange: Readonly<{
84
+ start: number;
85
+ end: number;
86
+ }>;
87
+ /** Block IDs that are pinned (always rendered regardless of scroll). */
88
+ readonly pinnedBlockIds: ReadonlySet<string>;
89
+ /**
90
+ * Perform the initial render of the document into the root element.
91
+ *
92
+ * Clears root children, creates spacer elements, renders the initial
93
+ * visible range of blocks, and measures their heights.
94
+ *
95
+ * @param doc - The RTIF document to render
96
+ * @param markRenderers - Optional mark renderer registry
97
+ * @param blockRenderers - Optional block renderer registry
98
+ * @param blockElementMap - Optional map to populate with block ID to element mappings
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * vp.renderInitial(doc, markRenderers, blockRenderers, blockElementMap);
103
+ * ```
104
+ */
105
+ renderInitial(doc: Document, markRenderers?: MarkRendererRegistry, blockRenderers?: BlockRendererRegistry, blockElementMap?: Map<string, HTMLElement>): void;
106
+ /**
107
+ * Reconcile the viewport after a document change.
108
+ *
109
+ * Rebuilds the spatial index preserving measured heights, recomputes
110
+ * the visible range, delegates to {@link reconcileBlock} for changed
111
+ * blocks, and updates spacer heights.
112
+ *
113
+ * @param prevDoc - The previous document state
114
+ * @param nextDoc - The new document state
115
+ * @param composingBlockId - Block ID under IME composition, or null
116
+ * @param markRenderers - Optional mark renderer registry
117
+ * @param blockRenderers - Optional block renderer registry
118
+ * @param blockElementMap - Optional map of block ID to element
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * vp.reconcile(prevDoc, nextDoc, null, markRenderers, blockRenderers, blockElementMap);
123
+ * ```
124
+ */
125
+ reconcile(prevDoc: Document, nextDoc: Document, composingBlockId: string | null, markRenderers?: MarkRendererRegistry, blockRenderers?: BlockRendererRegistry, blockElementMap?: Map<string, HTMLElement>): void;
126
+ /**
127
+ * Ensure a specific block index is rendered in the DOM.
128
+ *
129
+ * If the block is outside the current rendered range, the range is
130
+ * expanded to include it. Returns the block element, or null if the
131
+ * index is out of bounds.
132
+ *
133
+ * @param blockIndex - The 0-based block index to ensure is rendered
134
+ * @returns The block DOM element, or null if the index is invalid
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * const el = vp.ensureRendered(42);
139
+ * if (el) el.scrollIntoView();
140
+ * ```
141
+ */
142
+ ensureRendered(blockIndex: number): HTMLElement | null;
143
+ /**
144
+ * Pin a block so it stays rendered regardless of scroll position.
145
+ *
146
+ * Useful for blocks under active editing (e.g., IME composition)
147
+ * that must not be removed from the DOM.
148
+ *
149
+ * @param blockId - The block ID to pin
150
+ */
151
+ pin(blockId: string): void;
152
+ /**
153
+ * Unpin a previously pinned block.
154
+ *
155
+ * The block may be removed from the DOM on the next scroll event
156
+ * if it is outside the visible range.
157
+ *
158
+ * @param blockId - The block ID to unpin
159
+ */
160
+ unpin(blockId: string): void;
161
+ /**
162
+ * Handle a scroll event. Recomputes the visible range and adds/removes
163
+ * block elements as needed. Throttled via requestAnimationFrame.
164
+ */
165
+ onScroll(): void;
166
+ /**
167
+ * Measure actual DOM heights of all rendered block elements and update
168
+ * the spatial index with the measured values.
169
+ */
170
+ measureHeights(): void;
171
+ /**
172
+ * Temporarily render all blocks in the document.
173
+ *
174
+ * Uses a DocumentFragment to batch DOM insertions for better performance.
175
+ * Returns a restore function that removes non-visible blocks and
176
+ * restores spacer heights. Useful for operations that need all blocks
177
+ * in the DOM (e.g., find-and-replace, full-document selection sync).
178
+ *
179
+ * @returns A function that restores virtualized rendering
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * const restore = vp.expandAll();
184
+ * // ... perform operation that needs all blocks ...
185
+ * restore();
186
+ * ```
187
+ */
188
+ expandAll(): () => void;
189
+ /**
190
+ * Destroy the viewport, removing scroll listeners and cleaning up state.
191
+ *
192
+ * The root element's children (spacers, blocks) are NOT removed -- the
193
+ * caller is responsible for clearing the root if needed.
194
+ */
195
+ destroy(): void;
196
+ }
197
+ /**
198
+ * Walk DOM ancestors of an element to find the nearest scrollable container.
199
+ *
200
+ * Checks `getComputedStyle(el).overflowY` for `auto` or `scroll`. If no
201
+ * scrollable ancestor is found (including `document.body` and
202
+ * `document.documentElement`), returns `window`.
203
+ *
204
+ * @param el - The element to start searching from
205
+ * @returns The nearest scrollable ancestor, or `window`
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * const scroller = findScrollParent(editorRoot);
210
+ * scroller.addEventListener('scroll', onScroll);
211
+ * ```
212
+ */
213
+ export declare function findScrollParent(el: HTMLElement): HTMLElement | Window;
214
+ /**
215
+ * Create a virtual viewport for block-level DOM virtualization.
216
+ *
217
+ * The viewport renders only blocks within the visible scroll region (plus
218
+ * a configurable buffer), using spacer elements to maintain correct scroll
219
+ * height. As the user scrolls, blocks entering the viewport are created
220
+ * and blocks leaving are removed.
221
+ *
222
+ * @param config - Viewport configuration (root element, buffer size, etc.)
223
+ * @param doc - The initial RTIF document
224
+ * @returns A {@link VirtualViewport} instance
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * import { createVirtualViewport } from '@rtif-sdk/web';
229
+ *
230
+ * const vp = createVirtualViewport({ root: editorEl, bufferSize: 15 }, doc);
231
+ * vp.renderInitial(doc, markRenderers, blockRenderers, blockElementMap);
232
+ *
233
+ * // On document change:
234
+ * vp.reconcile(prevDoc, nextDoc, null, markRenderers, blockRenderers, blockElementMap);
235
+ *
236
+ * // Cleanup:
237
+ * vp.destroy();
238
+ * ```
239
+ */
240
+ export declare function createVirtualViewport(config: VirtualViewportConfig, doc: Document): VirtualViewport;
241
+ //# sourceMappingURL=virtual-viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-viewport.d.ts","sourceRoot":"","sources":["../src/virtual-viewport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAMjE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAE3B;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAEvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnD;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;CACjD;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAEpC,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEjE,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAE7C;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CACX,GAAG,EAAE,QAAQ,EACb,aAAa,CAAC,EAAE,oBAAoB,EACpC,cAAc,CAAC,EAAE,qBAAqB,EACtC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GACzC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CACP,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,QAAQ,EACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,aAAa,CAAC,EAAE,oBAAoB,EACpC,cAAc,CAAC,EAAE,qBAAqB,EACtC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GACzC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAEvD;;;;;;;OAOG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;OAGG;IACH,QAAQ,IAAI,IAAI,CAAC;IAEjB;;;OAGG;IACH,cAAc,IAAI,IAAI,CAAC;IAEvB;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,IAAI,MAAM,IAAI,CAAC;IAExB;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,CAUtE;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,QAAQ,GACZ,eAAe,CA6iBjB"}