@beyondwork/docx-react-component 1.0.130 → 1.0.132

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 (98) hide show
  1. package/dist/api/public-types.cjs +679 -157
  2. package/dist/api/public-types.d.cts +2 -2
  3. package/dist/api/public-types.d.ts +2 -2
  4. package/dist/api/public-types.js +5 -3
  5. package/dist/api/v3.cjs +371 -32
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{canonical-document-BMtONpgf.d.cts → canonical-document-CfZIc-fC.d.cts} +1 -1
  10. package/dist/{canonical-document-BMtONpgf.d.ts → canonical-document-CfZIc-fC.d.ts} +1 -1
  11. package/dist/{chunk-YLL7MF5C.js → chunk-43JAPM2F.js} +24 -17
  12. package/dist/{chunk-4YCWECLZ.js → chunk-4HGFJ6Z2.js} +1 -1
  13. package/dist/{chunk-HYHCRMR7.js → chunk-6736GA6J.js} +1 -1
  14. package/dist/{chunk-Q7Y57KOK.js → chunk-6TLZ6CMP.js} +2 -2
  15. package/dist/{chunk-DGA7M77X.js → chunk-ALWXYGXP.js} +2 -2
  16. package/dist/{chunk-PHMWH23E.js → chunk-C5LXKR54.js} +1 -1
  17. package/dist/{chunk-6TBLDBCL.js → chunk-CDEZGLQ3.js} +1 -1
  18. package/dist/{chunk-VRKK2CSZ.js → chunk-JVTDBX67.js} +2 -2
  19. package/dist/{chunk-THVM6EP5.js → chunk-LPLJZJT2.js} +1196 -35
  20. package/dist/{chunk-T5YYFDZB.js → chunk-N5FTU4HZ.js} +1 -1
  21. package/dist/{chunk-3YCQM2RV.js → chunk-QUTVR72L.js} +8 -7
  22. package/dist/{chunk-M7YRJX6V.js → chunk-RBWJHRNP.js} +1 -1
  23. package/dist/{chunk-A66ZVUAT.js → chunk-RYMMKOFI.js} +204 -10
  24. package/dist/{chunk-QXKQPUOM.js → chunk-SZ6BJA4Q.js} +3 -3
  25. package/dist/{chunk-A3GSNB4G.js → chunk-U3UMKA7B.js} +147 -13
  26. package/dist/{chunk-KNHMXKC6.js → chunk-UFPBYJMA.js} +2 -2
  27. package/dist/{chunk-35RHOE6I.js → chunk-UP2KDOYE.js} +6 -1162
  28. package/dist/{chunk-CI2TD3T4.js → chunk-W2I47J2Q.js} +1 -1
  29. package/dist/{chunk-7G5GR3VV.js → chunk-XYTWOJII.js} +5 -5
  30. package/dist/{chunk-WZDKNF37.js → chunk-YUHNDEV5.js} +7 -7
  31. package/dist/{chunk-ZVC23LKV.js → chunk-ZDYGRO2Z.js} +1 -1
  32. package/dist/compare.d.cts +1 -1
  33. package/dist/compare.d.ts +1 -1
  34. package/dist/core/commands/formatting-commands.d.cts +2 -2
  35. package/dist/core/commands/formatting-commands.d.ts +2 -2
  36. package/dist/core/commands/image-commands.cjs +312 -20
  37. package/dist/core/commands/image-commands.d.cts +2 -2
  38. package/dist/core/commands/image-commands.d.ts +2 -2
  39. package/dist/core/commands/image-commands.js +5 -5
  40. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  41. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  42. package/dist/core/commands/style-commands.d.cts +2 -2
  43. package/dist/core/commands/style-commands.d.ts +2 -2
  44. package/dist/core/commands/table-structure-commands.cjs +312 -20
  45. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  46. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  47. package/dist/core/commands/table-structure-commands.js +4 -4
  48. package/dist/core/commands/text-commands.cjs +312 -20
  49. package/dist/core/commands/text-commands.d.cts +2 -2
  50. package/dist/core/commands/text-commands.d.ts +2 -2
  51. package/dist/core/commands/text-commands.js +5 -5
  52. package/dist/core/selection/mapping.d.cts +2 -2
  53. package/dist/core/selection/mapping.d.ts +2 -2
  54. package/dist/core/state/editor-state.d.cts +2 -2
  55. package/dist/core/state/editor-state.d.ts +2 -2
  56. package/dist/index.cjs +3015 -2213
  57. package/dist/index.d.cts +5 -5
  58. package/dist/index.d.ts +5 -5
  59. package/dist/index.js +554 -99
  60. package/dist/io/docx-session.d.cts +4 -4
  61. package/dist/io/docx-session.d.ts +4 -4
  62. package/dist/io/docx-session.js +4 -4
  63. package/dist/legal.d.cts +1 -1
  64. package/dist/legal.d.ts +1 -1
  65. package/dist/legal.js +3 -3
  66. package/dist/{loader-B-aL5HGD.d.ts → loader-CfpeEPAa.d.ts} +3 -3
  67. package/dist/{loader-DiY_ZgKl.d.cts → loader-MAa8VpzW.d.cts} +3 -3
  68. package/dist/{public-types-gvubspUI.d.cts → public-types-Cjs8glST.d.ts} +137 -2
  69. package/dist/{public-types-DyqnxxO9.d.ts → public-types-KBS6JnOs.d.cts} +137 -2
  70. package/dist/public-types.cjs +679 -157
  71. package/dist/public-types.d.cts +2 -2
  72. package/dist/public-types.d.ts +2 -2
  73. package/dist/public-types.js +5 -3
  74. package/dist/runtime/collab.d.cts +3 -3
  75. package/dist/runtime/collab.d.ts +3 -3
  76. package/dist/runtime/document-runtime.cjs +371 -22
  77. package/dist/runtime/document-runtime.d.cts +2 -2
  78. package/dist/runtime/document-runtime.d.ts +2 -2
  79. package/dist/runtime/document-runtime.js +14 -14
  80. package/dist/{session-CDB0hohT.d.ts → session-CkoH8FoY.d.ts} +3 -3
  81. package/dist/{session-BUN6B-Vj.d.cts → session-wwe0Gib-.d.cts} +3 -3
  82. package/dist/session.d.cts +5 -5
  83. package/dist/session.d.ts +5 -5
  84. package/dist/session.js +5 -5
  85. package/dist/tailwind.cjs +492 -202
  86. package/dist/tailwind.d.cts +2 -2
  87. package/dist/tailwind.d.ts +2 -2
  88. package/dist/tailwind.js +7 -7
  89. package/dist/{types-C4bz3kDU.d.cts → types-B3SGRW0w.d.cts} +2 -2
  90. package/dist/{types-VWH6CRvG.d.ts → types-CH7NWqVL.d.ts} +2 -2
  91. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  92. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  93. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  94. package/dist/ui-tailwind.cjs +492 -202
  95. package/dist/ui-tailwind.d.cts +3 -3
  96. package/dist/ui-tailwind.d.ts +3 -3
  97. package/dist/ui-tailwind.js +7 -7
  98. package/package.json +4 -1
@@ -1,1164 +1,14 @@
1
1
  import {
2
- EMPTY_DECORATION_INDEX,
3
2
  PAGE_STACK_GAP_PX,
4
- defaultChromeReservations,
5
3
  resolveDefaultZoom
6
- } from "./chunk-THVM6EP5.js";
7
- import {
8
- storyTargetKey
9
- } from "./chunk-A3GSNB4G.js";
4
+ } from "./chunk-LPLJZJT2.js";
10
5
  import {
11
6
  MAIN_STORY_KEY,
12
7
  collectCanonicalLayoutInputs,
13
8
  collectStoryBlockContexts,
14
9
  createHeaderFooterStoryKey,
15
10
  createNoteStoryKey
16
- } from "./chunk-A66ZVUAT.js";
17
- import {
18
- MAIN_STORY_TARGET
19
- } from "./chunk-M2HUK3KF.js";
20
-
21
- // src/runtime/telemetry/perf-probe.ts
22
- var PREDICTED_LANE_COUNTERS = {
23
- applied: "predictions.applied",
24
- equivalent: "predictions.equivalent",
25
- adjusted: "predictions.adjusted",
26
- rejected: "predictions.rejected",
27
- rollback: "predictions.rollback",
28
- structuralDivergence: "predictions.structuralDivergence",
29
- bailBeforePredict: "predictions.bailBeforePredict",
30
- refreshSelectionOnly: "predictions.refresh.selectionOnly",
31
- refreshLocalTextEquivalent: "predictions.refresh.localTextEquivalent",
32
- refreshSurfaceOnly: "predictions.refresh.surfaceOnly",
33
- refreshFullProjection: "predictions.refresh.fullProjection",
34
- refreshBlocked: "predictions.refresh.blocked"
35
- };
36
- function startPerfProbe(kind) {
37
- const state = getEnabledState();
38
- if (!state) {
39
- return null;
40
- }
41
- const token = `${kind}-${state.nextToken ?? 0}`;
42
- state.nextToken = (state.nextToken ?? 0) + 1;
43
- state.pending ??= {};
44
- state.pending[token] = {
45
- kind,
46
- startedAt: performance.now()
47
- };
48
- return token;
49
- }
50
- function finishPerfProbe(token) {
51
- if (!token) {
52
- return null;
53
- }
54
- const state = getEnabledState();
55
- if (!state?.pending?.[token]) {
56
- return null;
57
- }
58
- const pending = state.pending[token];
59
- delete state.pending[token];
60
- const sample = {
61
- token,
62
- kind: pending.kind,
63
- durationMs: performance.now() - pending.startedAt,
64
- recordedAt: Date.now()
65
- };
66
- pushSample(state, sample);
67
- return sample;
68
- }
69
- function recordPerfSample(kind, durationMs = 0) {
70
- const state = getEnabledState();
71
- if (!state) {
72
- return null;
73
- }
74
- const token = `${kind}-${state.nextToken ?? 0}`;
75
- state.nextToken = (state.nextToken ?? 0) + 1;
76
- const sample = {
77
- token,
78
- kind,
79
- durationMs,
80
- recordedAt: Date.now()
81
- };
82
- pushSample(state, sample);
83
- return sample;
84
- }
85
- function incrementInvalidationCounter(counter, amount = 1) {
86
- const state = getEnabledState();
87
- if (!state) {
88
- return 0;
89
- }
90
- state.invalidationCounts ??= {};
91
- state.invalidationCounts[counter] = (state.invalidationCounts[counter] ?? 0) + amount;
92
- return state.invalidationCounts[counter];
93
- }
94
- function getEnabledState() {
95
- if (typeof window === "undefined") {
96
- return null;
97
- }
98
- const state = window.__DOCX_REACT_PERF_PROBE__;
99
- if (!state?.enabled) {
100
- return null;
101
- }
102
- return state;
103
- }
104
- function pushSample(state, sample) {
105
- state.samples ??= [];
106
- state.samples.push(sample);
107
- const maxSamples = state.maxSamples ?? 20;
108
- if (state.samples.length > maxSamples) {
109
- state.samples.splice(0, state.samples.length - maxSamples);
110
- }
111
- }
112
-
113
- // src/runtime/render/decoration-resolver.ts
114
- function resolveDecorationIndex(input) {
115
- const workflow = [];
116
- const comments = [];
117
- const revisions = [];
118
- const search = [];
119
- const locked = [];
120
- if (input.workflowSegments) {
121
- for (const segment of input.workflowSegments) {
122
- const frame = input.anchorIndex.bySelection(
123
- segment.fromOffset,
124
- segment.toOffset
125
- );
126
- if (!frame) continue;
127
- workflow.push({
128
- kind: "workflow",
129
- refId: segment.scopeId,
130
- frame
131
- });
132
- }
133
- }
134
- if (input.comments) {
135
- for (const thread of input.comments.threads) {
136
- const frame = resolveRange(
137
- input.anchorIndex,
138
- thread.from,
139
- thread.to
140
- );
141
- if (!frame) continue;
142
- comments.push({
143
- kind: "comment",
144
- refId: thread.commentId,
145
- frame
146
- });
147
- void asCommentThread(thread);
148
- }
149
- }
150
- if (input.revisions) {
151
- for (const revision of input.revisions.revisions) {
152
- const frame = resolveRange(
153
- input.anchorIndex,
154
- revision.from,
155
- revision.to
156
- );
157
- if (!frame) continue;
158
- revisions.push({
159
- kind: "revision",
160
- refId: revision.revisionId,
161
- frame
162
- });
163
- void asRevisionEntry(revision);
164
- }
165
- }
166
- if (input.searchMatches) {
167
- for (const match of input.searchMatches) {
168
- const frame = resolveRange(input.anchorIndex, match.from, match.to);
169
- if (!frame) continue;
170
- search.push({
171
- kind: "search",
172
- refId: match.matchId,
173
- frame
174
- });
175
- }
176
- }
177
- if (input.lockedRanges) {
178
- for (const lock of input.lockedRanges) {
179
- const frame = resolveRange(input.anchorIndex, lock.from, lock.to);
180
- if (!frame) continue;
181
- locked.push({
182
- kind: "locked",
183
- refId: lock.lockId,
184
- frame
185
- });
186
- }
187
- }
188
- return { workflow, comments, revisions, search, locked };
189
- }
190
- function resolveRange(anchorIndex, from, to) {
191
- if (from >= to) {
192
- return anchorIndex.byRuntimeOffset(from);
193
- }
194
- return anchorIndex.bySelection(from, to);
195
- }
196
- function asCommentThread(thread) {
197
- return thread;
198
- }
199
- function asRevisionEntry(entry) {
200
- return entry;
201
- }
202
-
203
- // src/runtime/render/block-fragment-projection.ts
204
- function classifyBlockKind(blockId) {
205
- if (blockId.startsWith("paragraph")) return "paragraph";
206
- if (blockId.startsWith("table")) return "table";
207
- if (blockId.startsWith("placeholder-culled-")) return "opaque";
208
- if (blockId.startsWith("opaque")) return "opaque";
209
- if (blockId.startsWith("section-break")) return "opaque";
210
- if (blockId.startsWith("sdt")) return "opaque";
211
- if (blockId.startsWith("custom-xml")) return "opaque";
212
- if (blockId.startsWith("alt-chunk")) return "opaque";
213
- if (blockId.startsWith("synthetic")) return "synthetic";
214
- return "paragraph";
215
- }
216
-
217
- // src/runtime/render/render-frame-diff.ts
218
- function diffRenderFrames(prev, next) {
219
- if (!prev) {
220
- return {
221
- addedPages: next.pages.map((p) => p.page.pageIndex),
222
- removedPages: [],
223
- unchangedPages: [],
224
- changedPages: []
225
- };
226
- }
227
- const prevByIndex = /* @__PURE__ */ new Map();
228
- for (const page of prev.pages) {
229
- prevByIndex.set(page.page.pageIndex, page);
230
- }
231
- const nextIndices = /* @__PURE__ */ new Set();
232
- for (const page of next.pages) {
233
- nextIndices.add(page.page.pageIndex);
234
- }
235
- const addedPages = [];
236
- const removedPages = [];
237
- const unchangedPages = [];
238
- const changedPages = [];
239
- for (const nextPage of next.pages) {
240
- const pageIndex = nextPage.page.pageIndex;
241
- const prevPage = prevByIndex.get(pageIndex);
242
- if (!prevPage) {
243
- addedPages.push(pageIndex);
244
- continue;
245
- }
246
- const regions = diffPage(prevPage, nextPage, prev.decorationIndex, next.decorationIndex);
247
- const frameChanged = !rectEquals(prevPage.frame, nextPage.frame);
248
- const reservationsChanged = !reservationsEqual(
249
- prevPage.chromeReservations,
250
- nextPage.chromeReservations
251
- );
252
- if (regions.length === 0 && !frameChanged && !reservationsChanged) {
253
- unchangedPages.push(pageIndex);
254
- } else {
255
- changedPages.push({
256
- pageIndex,
257
- regions,
258
- ...frameChanged ? { pageFrameChanged: true } : {}
259
- });
260
- }
261
- }
262
- for (const prevPage of prev.pages) {
263
- if (!nextIndices.has(prevPage.page.pageIndex)) {
264
- removedPages.push(prevPage.page.pageIndex);
265
- }
266
- }
267
- return { addedPages, removedPages, unchangedPages, changedPages };
268
- }
269
- function createPagePatchPlan(prev, next, diff = diffRenderFrames(prev, next), options = {}) {
270
- const prevByIndex = indexPagesByIndex(prev?.pages ?? []);
271
- const nextByIndex = indexPagesByIndex(next.pages);
272
- const addedPages = diff.addedPages.map(
273
- (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
274
- );
275
- const removedPages = diff.removedPages.map(
276
- (pageIndex) => pageIdForIndex(prevByIndex, pageIndex)
277
- );
278
- const unchangedPages = diff.unchangedPages.map(
279
- (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
280
- );
281
- const changedPages = diff.changedPages.map(
282
- (entry) => createPagePatchEntry(entry, pageIdForIndex(nextByIndex, entry.pageIndex), options)
283
- );
284
- return {
285
- layoutRevision: options.layoutRevision ?? next.revision,
286
- geometryRevision: options.geometryRevision ?? next.revision,
287
- addedPages,
288
- removedPages,
289
- unchangedPages,
290
- changedPages,
291
- mountChanges: resolveMountChanges({
292
- addedPages,
293
- removedPages,
294
- mountedPageIds: options.mountedPageIds,
295
- requestedMountPageIds: options.requestedMountPageIds
296
- })
297
- };
298
- }
299
- function createPagePatchEntry(entry, pageId, options) {
300
- const regionChanges = entry.regions.map((region) => region.kind);
301
- const fragmentChanges = uniqueStrings(
302
- entry.regions.flatMap((region) => region.changedBlockIds)
303
- );
304
- const overlayLaneChanges = !entry.pageFrameChanged && entry.regions.length === 0 ? ["chrome-reservations"] : [];
305
- return {
306
- pageId,
307
- pageIndex: entry.pageIndex,
308
- frameChanged: entry.pageFrameChanged === true,
309
- regionChanges,
310
- fragmentChanges,
311
- lineBoxChanges: fragmentChanges,
312
- overlayLaneChanges,
313
- reason: options.reason ?? (overlayLaneChanges.length > 0 ? "overlay" : "layout")
314
- };
315
- }
316
- function resolveMountChanges(input) {
317
- if (!input.mountedPageIds || !input.requestedMountPageIds) {
318
- return {
319
- mountPageIds: input.addedPages,
320
- unmountPageIds: input.removedPages
321
- };
322
- }
323
- const mounted = new Set(input.mountedPageIds);
324
- const requested = new Set(input.requestedMountPageIds);
325
- return {
326
- mountPageIds: input.requestedMountPageIds.filter((pageId) => !mounted.has(pageId)),
327
- unmountPageIds: input.mountedPageIds.filter((pageId) => !requested.has(pageId))
328
- };
329
- }
330
- function indexPagesByIndex(pages) {
331
- return new Map(pages.map((page) => [page.page.pageIndex, page]));
332
- }
333
- function pageIdForIndex(pages, pageIndex) {
334
- return pages.get(pageIndex)?.page.pageId ?? `page:${pageIndex}`;
335
- }
336
- function uniqueStrings(values) {
337
- return [...new Set(values)];
338
- }
339
- function diffPage(prev, next, prevIndex, nextIndex) {
340
- const changed = [];
341
- const bodyChanges = diffRegion(prev.regions.body, next.regions.body, prevIndex, nextIndex);
342
- if (bodyChanges.length > 0) {
343
- changed.push({ kind: "body", changedBlockIds: bodyChanges });
344
- }
345
- const headerChanges = diffOptionalRegion(
346
- prev.regions.header,
347
- next.regions.header,
348
- prevIndex,
349
- nextIndex
350
- );
351
- if (headerChanges.length > 0) {
352
- changed.push({ kind: "header", changedBlockIds: headerChanges });
353
- }
354
- const footerChanges = diffOptionalRegion(
355
- prev.regions.footer,
356
- next.regions.footer,
357
- prevIndex,
358
- nextIndex
359
- );
360
- if (footerChanges.length > 0) {
361
- changed.push({ kind: "footer", changedBlockIds: footerChanges });
362
- }
363
- const prevFoot = prev.regions.footnotes ?? [];
364
- const nextFoot = next.regions.footnotes ?? [];
365
- if (prevFoot.length !== nextFoot.length) {
366
- changed.push({ kind: "footnote-area", changedBlockIds: ["<count-changed>"] });
367
- } else {
368
- for (let i = 0; i < prevFoot.length; i += 1) {
369
- const fChanges = diffRegion(prevFoot[i], nextFoot[i], prevIndex, nextIndex);
370
- if (fChanges.length > 0) {
371
- changed.push({ kind: "footnote-area", changedBlockIds: fChanges });
372
- }
373
- }
374
- }
375
- return changed;
376
- }
377
- function diffOptionalRegion(prev, next, prevIndex, nextIndex) {
378
- if (!prev && !next) return [];
379
- if (!prev && next) return ["<added>"];
380
- if (prev && !next) return ["<removed>"];
381
- return diffRegion(prev, next, prevIndex, nextIndex);
382
- }
383
- function diffRegion(prev, next, prevIndex, nextIndex) {
384
- const changed = [];
385
- if (!rectEquals(prev.frame, next.frame)) {
386
- changed.push("<region-frame>");
387
- }
388
- const prevBlocks = /* @__PURE__ */ new Map();
389
- for (const block of prev.blocks) {
390
- prevBlocks.set(block.fragment.blockId, block);
391
- }
392
- const nextIds = /* @__PURE__ */ new Set();
393
- for (const block of next.blocks) {
394
- nextIds.add(block.fragment.blockId);
395
- const prevBlock = prevBlocks.get(block.fragment.blockId);
396
- if (!prevBlock) {
397
- changed.push(block.fragment.blockId);
398
- continue;
399
- }
400
- if (!blocksStructurallyEqual(prevBlock, block, prevIndex, nextIndex)) {
401
- changed.push(block.fragment.blockId);
402
- }
403
- }
404
- for (const blockId of prevBlocks.keys()) {
405
- if (!nextIds.has(blockId)) changed.push(blockId);
406
- }
407
- return changed;
408
- }
409
- function blocksStructurallyEqual(a, b, aIndex, bIndex) {
410
- if (a.kind !== b.kind) return false;
411
- if (a.fragment.regionKind !== b.fragment.regionKind) return false;
412
- if (a.fragment.from !== b.fragment.from) return false;
413
- if (a.fragment.to !== b.fragment.to) return false;
414
- if (!rectEquals(a.frame, b.frame)) return false;
415
- if (a.lines.length !== b.lines.length) return false;
416
- for (let i = 0; i < a.lines.length; i += 1) {
417
- if (!rectEquals(a.lines[i].frame, b.lines[i].frame)) return false;
418
- }
419
- const aHash = decorationHashForBlock(a.frame, aIndex);
420
- const bHash = decorationHashForBlock(b.frame, bIndex);
421
- if (aHash !== bHash) return false;
422
- return true;
423
- }
424
- function decorationHashForBlock(blockFrame, index) {
425
- const tokens = [];
426
- for (const lane of [index.workflow, index.comments, index.revisions, index.search, index.locked]) {
427
- for (const entry of lane) {
428
- if (rectIntersects(entry.frame, blockFrame)) {
429
- tokens.push(`${entry.kind}:${entry.refId}`);
430
- }
431
- }
432
- }
433
- tokens.sort();
434
- return tokens.join("|");
435
- }
436
- function reservationsEqual(a, b) {
437
- return a.railLaneTwips === b.railLaneTwips && a.balloonLaneTwips === b.balloonLaneTwips && a.footnoteAreaTwips === b.footnoteAreaTwips && a.pageFrameWidthPx === b.pageFrameWidthPx && a.pageFrameHeightPx === b.pageFrameHeightPx;
438
- }
439
- var RECT_EPS = 0.1;
440
- function rectEquals(a, b) {
441
- return Math.abs(a.leftPx - b.leftPx) < RECT_EPS && Math.abs(a.topPx - b.topPx) < RECT_EPS && Math.abs(a.widthPx - b.widthPx) < RECT_EPS && Math.abs(a.heightPx - b.heightPx) < RECT_EPS;
442
- }
443
- function rectIntersects(a, b) {
444
- return !(a.leftPx + a.widthPx <= b.leftPx || b.leftPx + b.widthPx <= a.leftPx || a.topPx + a.heightPx <= b.topPx || b.topPx + b.heightPx <= a.topPx);
445
- }
446
-
447
- // src/runtime/render/render-kernel.ts
448
- function sumDeltasBefore(deltas, runtimeOffset) {
449
- let total = 0;
450
- for (const d of deltas) {
451
- if (d.fromRuntime <= runtimeOffset) total += d.delta;
452
- }
453
- return total;
454
- }
455
- function createRenderKernel(input) {
456
- const { facet } = input;
457
- const getActiveStory = input.getActiveStory ?? (() => MAIN_STORY_TARGET);
458
- let zoom = input.initialZoom ?? resolveDefaultZoom();
459
- let cache = null;
460
- let lastEmittedFrame = null;
461
- let diCacheKey = null;
462
- let diCacheValue = null;
463
- const listeners = /* @__PURE__ */ new Set();
464
- const unsubscribeFacet = facet.subscribe((event) => {
465
- if (event.kind === "layout_recomputed" || event.kind === "incremental_relayout" || event.kind === "measurement_backend_ready" || event.kind === "zoom_changed") {
466
- cache = null;
467
- }
468
- });
469
- void unsubscribeFacet;
470
- function emit(event) {
471
- for (const listener of listeners) {
472
- try {
473
- listener(event);
474
- } catch {
475
- }
476
- }
477
- }
478
- function buildFrame(options) {
479
- const t0 = typeof performance !== "undefined" ? performance.now() : 0;
480
- const activeStory = options?.story ?? getActiveStory();
481
- const measurementFidelity = facet.getMeasurementFidelity();
482
- const rawPages = facet.getPages();
483
- const pageRange = options?.pageRange;
484
- const filteredPages = pageRange ? rawPages.filter(
485
- (p) => p.pageIndex >= pageRange.fromPageIndex && p.pageIndex <= pageRange.toPageIndex
486
- ) : rawPages;
487
- let y = 0;
488
- const renderPages = [];
489
- for (const page of filteredPages) {
490
- const renderPage = buildPage(page, y, zoom, activeStory, facet);
491
- renderPages.push(renderPage);
492
- y += renderPage.frame.heightPx + PAGE_STACK_GAP_PX;
493
- }
494
- const pendingDeltas = input.getPendingOpDeltas?.() ?? [];
495
- const baseAnchorIndex = buildAnchorIndex(
496
- renderPages,
497
- pendingDeltas,
498
- zoom.pxPerTwip
499
- );
500
- const revision = filteredPages[0] ? Number(extractRevisionFromPageId(filteredPages[0].pageId)) : 0;
501
- const includeDecorations = options?.includeDecorations ?? true;
502
- const sources = input.getDecorationSources?.();
503
- const hasSources = sources !== void 0 && (sources.workflowSegments && sources.workflowSegments.length > 0 || (sources.comments?.threads?.length ?? 0) > 0 || (sources.revisions?.revisions?.length ?? 0) > 0 || sources.searchMatches && sources.searchMatches.length > 0 || sources.lockedRanges && sources.lockedRanges.length > 0);
504
- const newDIKey = {
505
- revision: Number.isFinite(revision) ? revision : 0,
506
- activeStoryKind: activeStory.kind,
507
- zoomPxPerTwip: zoom.pxPerTwip,
508
- workflowSegments: sources?.workflowSegments,
509
- comments: sources?.comments,
510
- revisions: sources?.revisions,
511
- searchMatches: sources?.searchMatches,
512
- lockedRanges: sources?.lockedRanges
513
- };
514
- const diCacheHit = hasSources && diCacheKey !== null && diCacheValue !== null && diCacheKey.revision === newDIKey.revision && diCacheKey.activeStoryKind === newDIKey.activeStoryKind && diCacheKey.zoomPxPerTwip === newDIKey.zoomPxPerTwip && diCacheKey.workflowSegments === newDIKey.workflowSegments && diCacheKey.comments === newDIKey.comments && diCacheKey.revisions === newDIKey.revisions && diCacheKey.searchMatches === newDIKey.searchMatches && diCacheKey.lockedRanges === newDIKey.lockedRanges;
515
- let decorationIndex;
516
- if (!includeDecorations) {
517
- decorationIndex = EMPTY_DECORATION_INDEX;
518
- } else if (hasSources) {
519
- if (diCacheHit) {
520
- decorationIndex = diCacheValue;
521
- } else {
522
- decorationIndex = resolveDecorationIndex({ anchorIndex: baseAnchorIndex, ...sources });
523
- diCacheKey = newDIKey;
524
- diCacheValue = decorationIndex;
525
- }
526
- } else {
527
- decorationIndex = buildDecorationIndex(renderPages);
528
- }
529
- const anchorIndex = buildAnchorIndex(
530
- renderPages,
531
- pendingDeltas,
532
- zoom.pxPerTwip,
533
- decorationIndex
534
- );
535
- const frame = {
536
- revision: Number.isFinite(revision) ? revision : 0,
537
- measurementFidelity,
538
- activeStory,
539
- zoom: { ...zoom },
540
- pages: renderPages,
541
- decorationIndex,
542
- anchorIndex
543
- };
544
- if (t0 > 0) recordPerfSample("render.frame_build", performance.now() - t0);
545
- return frame;
546
- }
547
- return {
548
- getRenderFrame(options) {
549
- const rebuild = options !== void 0 || cache === null;
550
- if (!rebuild && cache) {
551
- return cache.frame;
552
- }
553
- const frame = buildFrame(options);
554
- if (options === void 0) {
555
- cache = { revision: frame.revision, frame };
556
- emit({ kind: "frame_built", revision: frame.revision, reason: "full" });
557
- const diffT0 = typeof performance !== "undefined" ? performance.now() : 0;
558
- const diff = diffRenderFrames(lastEmittedFrame, frame);
559
- const patchPlan = createPagePatchPlan(lastEmittedFrame, frame, diff);
560
- recordPagePatchPlanTelemetry(patchPlan);
561
- if (diffT0 > 0) {
562
- recordPerfSample("render.frame_diff", performance.now() - diffT0);
563
- }
564
- emit({ kind: "frame_diff", revision: frame.revision, diff, patchPlan });
565
- lastEmittedFrame = frame;
566
- }
567
- return frame;
568
- },
569
- getZoom() {
570
- return { ...zoom };
571
- },
572
- setZoom(next) {
573
- zoom = { ...next };
574
- cache = null;
575
- },
576
- subscribe(listener) {
577
- listeners.add(listener);
578
- return () => {
579
- listeners.delete(listener);
580
- };
581
- },
582
- invalidate() {
583
- cache = null;
584
- }
585
- };
586
- }
587
- function recordPagePatchPlanTelemetry(plan) {
588
- incrementInvalidationCounter(
589
- "pageRender.patch.addedPages",
590
- plan.addedPages.length
591
- );
592
- incrementInvalidationCounter(
593
- "pageRender.patch.removedPages",
594
- plan.removedPages.length
595
- );
596
- incrementInvalidationCounter(
597
- "pageRender.patch.unchangedPages",
598
- plan.unchangedPages.length
599
- );
600
- incrementInvalidationCounter(
601
- "pageRender.patch.changedFragments",
602
- plan.changedPages.reduce(
603
- (total, page) => total + page.fragmentChanges.length,
604
- 0
605
- )
606
- );
607
- incrementInvalidationCounter(
608
- "pageRender.patch.mountedPages",
609
- plan.mountChanges.mountPageIds.length
610
- );
611
- incrementInvalidationCounter(
612
- "pageRender.patch.unmountedPages",
613
- plan.mountChanges.unmountPageIds.length
614
- );
615
- }
616
- function buildPage(page, topPx, zoom, activeStory, facet) {
617
- const layout = page.layout;
618
- const widthPx = layout.pageWidth * zoom.pxPerTwip;
619
- const heightPx = layout.pageHeight * zoom.pxPerTwip;
620
- const frame = {
621
- leftPx: 0,
622
- topPx,
623
- widthPx,
624
- heightPx
625
- };
626
- const bodyRegion = buildBodyRegion(
627
- page,
628
- topPx,
629
- zoom,
630
- activeStory,
631
- facet
632
- );
633
- const regions = {
634
- body: bodyRegion
635
- };
636
- if (page.stories.header) {
637
- regions.header = buildHeaderFooterRegion(
638
- page,
639
- topPx,
640
- zoom,
641
- "header",
642
- page.stories.header,
643
- facet
644
- );
645
- }
646
- if (page.stories.footer) {
647
- regions.footer = buildHeaderFooterRegion(
648
- page,
649
- topPx,
650
- zoom,
651
- "footer",
652
- page.stories.footer,
653
- facet
654
- );
655
- }
656
- const footnoteRegions = buildFootnoteRegions(page, topPx, zoom, facet);
657
- if (footnoteRegions.length > 0) {
658
- regions.footnotes = footnoteRegions;
659
- }
660
- const chromeReservations = {
661
- ...defaultChromeReservations(layout, zoom)
662
- };
663
- return {
664
- page,
665
- frame,
666
- regions,
667
- chromeReservations
668
- };
669
- }
670
- function buildBodyRegion(page, pageTopPx, zoom, activeStory, facet) {
671
- const layout = page.layout;
672
- const bodyLeftTwips = layout.marginLeft;
673
- const bodyTopTwips = layout.marginTop;
674
- const bodyWidthTwips = page.regions.body.widthTwips;
675
- const bodyHeightTwips = page.regions.body.heightTwips;
676
- const regionFrame = {
677
- leftPx: bodyLeftTwips * zoom.pxPerTwip,
678
- topPx: pageTopPx + bodyTopTwips * zoom.pxPerTwip,
679
- widthPx: bodyWidthTwips * zoom.pxPerTwip,
680
- heightPx: bodyHeightTwips * zoom.pxPerTwip
681
- };
682
- const fragments = facet.getFragmentsForPage(page.pageIndex);
683
- const bodyLineBoxes = facet.getLineBoxes(page.pageIndex, { region: "body" });
684
- const blocks = [];
685
- let blockY = regionFrame.topPx;
686
- const totalFragmentHeight = fragments.reduce(
687
- (acc, fragment) => acc + Math.max(0, fragment.heightTwips),
688
- 0
689
- );
690
- for (const fragment of fragments) {
691
- if (fragment.regionKind !== "body") continue;
692
- const fragmentHeightTwips = fragment.heightTwips > 0 ? fragment.heightTwips : totalFragmentHeight === 0 ? bodyHeightTwips / Math.max(1, fragments.length) : 0;
693
- const blockHeightPx = fragmentHeightTwips * zoom.pxPerTwip;
694
- const fallbackBlockFrame = {
695
- leftPx: regionFrame.leftPx,
696
- topPx: blockY,
697
- widthPx: regionFrame.widthPx,
698
- heightPx: blockHeightPx
699
- };
700
- const blockLines = bodyLineBoxes.filter((box) => box.fragmentId === fragment.fragmentId).map((box) => {
701
- const lineFrame = lineFrameFromPublicBox(
702
- box,
703
- regionFrame,
704
- pageTopPx,
705
- bodyTopTwips,
706
- zoom
707
- );
708
- const anchors = [
709
- {
710
- runtimeOffset: fragment.from,
711
- frame: lineFrame,
712
- fragmentId: fragment.fragmentId,
713
- blockId: fragment.blockId
714
- }
715
- ];
716
- return {
717
- line: box,
718
- frame: lineFrame,
719
- anchors
720
- };
721
- });
722
- const kind = classifyBlockKind(fragment.blockId);
723
- const blockFrame = blockFrameFromLineFacts(
724
- fallbackBlockFrame,
725
- kind,
726
- blockLines
727
- );
728
- const tablePlan = kind === "table" ? facet.getTableRenderPlan(fragment.blockId, page.pageIndex) : void 0;
729
- blocks.push({
730
- fragment,
731
- frame: blockFrame,
732
- kind,
733
- lines: blockLines,
734
- blockDecorations: [],
735
- ...tablePlan !== void 0 ? { tablePlan } : {}
736
- });
737
- blockY = Math.max(blockY + blockHeightPx, blockFrame.topPx + blockFrame.heightPx);
738
- }
739
- return {
740
- storyTarget: activeStory,
741
- region: page.regions.body,
742
- frame: regionFrame,
743
- blocks
744
- };
745
- }
746
- function lineFrameFromPublicBox(box, regionFrame, pageTopPx, bodyTopTwips, zoom) {
747
- if (box.rectTwips) {
748
- return projectPageTwipsRectToFrame(box.rectTwips, pageTopPx, zoom);
749
- }
750
- const lineTopPx = pageTopPx + (bodyTopTwips + box.baselineTwips) * zoom.pxPerTwip;
751
- return {
752
- leftPx: regionFrame.leftPx,
753
- topPx: lineTopPx,
754
- widthPx: Math.min(
755
- regionFrame.widthPx,
756
- box.widthTwips * zoom.pxPerTwip
757
- ),
758
- heightPx: box.heightTwips * zoom.pxPerTwip
759
- };
760
- }
761
- function projectPageTwipsRectToFrame(rect, pageTopPx, zoom) {
762
- return {
763
- leftPx: rect.xTwips * zoom.pxPerTwip,
764
- topPx: pageTopPx + rect.yTwips * zoom.pxPerTwip,
765
- widthPx: rect.widthTwips * zoom.pxPerTwip,
766
- heightPx: rect.heightTwips * zoom.pxPerTwip
767
- };
768
- }
769
- function blockFrameFromLineFacts(fallback, kind, lines) {
770
- const union = unionRenderLineFrames(lines);
771
- if (!union) return fallback;
772
- if (kind === "paragraph") return union;
773
- if (fallback.widthPx <= 0 || fallback.heightPx <= 0) return union;
774
- return fallback;
775
- }
776
- function unionRenderLineFrames(lines) {
777
- let left = Number.POSITIVE_INFINITY;
778
- let top = Number.POSITIVE_INFINITY;
779
- let right = Number.NEGATIVE_INFINITY;
780
- let bottom = Number.NEGATIVE_INFINITY;
781
- for (const line of lines) {
782
- if (line.frame.widthPx <= 0 || line.frame.heightPx <= 0) continue;
783
- left = Math.min(left, line.frame.leftPx);
784
- top = Math.min(top, line.frame.topPx);
785
- right = Math.max(right, line.frame.leftPx + line.frame.widthPx);
786
- bottom = Math.max(bottom, line.frame.topPx + line.frame.heightPx);
787
- }
788
- if (!Number.isFinite(left) || !Number.isFinite(top)) return null;
789
- return {
790
- leftPx: left,
791
- topPx: top,
792
- widthPx: Math.max(0, right - left),
793
- heightPx: Math.max(0, bottom - top)
794
- };
795
- }
796
- function buildHeaderFooterRegion(page, pageTopPx, zoom, kind, storyTarget, facet) {
797
- const layout = page.layout;
798
- const fallbackWidthTwips = layout.pageWidth - layout.marginLeft - layout.marginRight;
799
- const fallbackTopTwips = kind === "header" ? layout.headerMargin ?? 720 : layout.pageHeight - layout.marginBottom;
800
- const fallbackHeightTwips = kind === "header" ? Math.max(0, layout.marginTop - (layout.headerMargin ?? 720)) : Math.max(0, layout.marginBottom - (layout.footerMargin ?? 720));
801
- const region = (kind === "header" ? page.regions.header : page.regions.footer) ?? {
802
- kind,
803
- originTwips: fallbackTopTwips,
804
- widthTwips: fallbackWidthTwips,
805
- heightTwips: fallbackHeightTwips,
806
- fragmentCount: 0
807
- };
808
- const frame = {
809
- leftPx: layout.marginLeft * zoom.pxPerTwip,
810
- topPx: pageTopPx + region.originTwips * zoom.pxPerTwip,
811
- widthPx: region.widthTwips * zoom.pxPerTwip,
812
- heightPx: region.heightTwips * zoom.pxPerTwip
813
- };
814
- const regionBlocks = facet.getStoryBlocksForRegion(page.pageIndex, kind);
815
- const blocks = projectRegionBlocks(
816
- regionBlocks,
817
- frame,
818
- zoom.pxPerTwip,
819
- page.pageId,
820
- page.pageIndex,
821
- kind
822
- );
823
- return {
824
- storyTarget,
825
- region,
826
- frame,
827
- blocks
828
- };
829
- }
830
- function buildFootnoteRegions(page, pageTopPx, zoom, facet) {
831
- const footnoteRegions = page.regions.footnotes;
832
- if (!footnoteRegions || footnoteRegions.length === 0) return [];
833
- const regionBlocks = facet.getStoryBlocksForRegion(
834
- page.pageIndex,
835
- "footnote-area"
836
- );
837
- if (regionBlocks.length === 0) return [];
838
- const results = [];
839
- let cursor = 0;
840
- for (const region of footnoteRegions) {
841
- const frame = {
842
- leftPx: page.layout.marginLeft * zoom.pxPerTwip,
843
- topPx: pageTopPx + region.originTwips * zoom.pxPerTwip,
844
- widthPx: region.widthTwips * zoom.pxPerTwip,
845
- heightPx: region.heightTwips * zoom.pxPerTwip
846
- };
847
- const blocksForThisRegion = footnoteRegions.length === 1 ? regionBlocks : regionBlocks.slice(cursor, cursor + region.fragmentCount);
848
- cursor += region.fragmentCount;
849
- const blocks = projectRegionBlocks(
850
- blocksForThisRegion,
851
- frame,
852
- zoom.pxPerTwip,
853
- page.pageId,
854
- page.pageIndex,
855
- "footnote-area"
856
- );
857
- const firstNote = page.noteAllocations.find(
858
- (alloc) => alloc.noteKind === "footnote"
859
- );
860
- const storyTarget = firstNote ? { kind: "footnote", noteId: firstNote.noteId } : MAIN_STORY_TARGET;
861
- results.push({
862
- storyTarget,
863
- region,
864
- frame,
865
- blocks
866
- });
867
- }
868
- return results;
869
- }
870
- function projectRegionBlocks(regionBlocks, regionFrame, pxPerTwip, pageId, pageIndex, regionKind) {
871
- const blocks = [];
872
- let y = regionFrame.topPx;
873
- for (let i = 0; i < regionBlocks.length; i += 1) {
874
- const regionBlock = regionBlocks[i];
875
- const blockHeightPx = Math.max(0, regionBlock.heightTwips) * pxPerTwip;
876
- const blockFrame = {
877
- leftPx: regionFrame.leftPx,
878
- topPx: y,
879
- widthPx: regionFrame.widthPx,
880
- heightPx: blockHeightPx
881
- };
882
- const fragment = {
883
- fragmentId: regionBlock.fragmentId,
884
- blockId: regionBlock.blockId,
885
- pageId,
886
- pageIndex,
887
- regionKind,
888
- from: regionBlock.runtimeFromOffset,
889
- to: regionBlock.runtimeToOffset,
890
- heightTwips: regionBlock.heightTwips,
891
- orderInRegion: i
892
- };
893
- blocks.push({
894
- fragment,
895
- frame: blockFrame,
896
- kind: classifyBlockKind(regionBlock.blockId),
897
- lines: [],
898
- blockDecorations: []
899
- });
900
- y += blockHeightPx;
901
- }
902
- return blocks;
903
- }
904
- function buildAnchorIndex(pages, pendingDeltas = [], pxPerTwip = 1, decorationIndex = EMPTY_DECORATION_INDEX) {
905
- const byRuntimeOffset = /* @__PURE__ */ new Map();
906
- const byRuntimeOffsetByStory = /* @__PURE__ */ new Map();
907
- const byFragmentId = /* @__PURE__ */ new Map();
908
- const byBlockId = /* @__PURE__ */ new Map();
909
- const byPageIndex = /* @__PURE__ */ new Map();
910
- const tableCellRects = /* @__PURE__ */ new Map();
911
- const tableColumnEdges = /* @__PURE__ */ new Map();
912
- const tableRowEdges = /* @__PURE__ */ new Map();
913
- const recordBlock = (block, offsetMap) => {
914
- byFragmentId.set(block.fragment.fragmentId, block.frame);
915
- byBlockId.set(block.fragment.blockId, block.frame);
916
- offsetMap.set(block.fragment.from, block.frame);
917
- for (const line of block.lines) {
918
- for (const anchor of line.anchors) {
919
- offsetMap.set(anchor.runtimeOffset, anchor.frame);
920
- }
921
- }
922
- if (block.kind === "table" && block.tablePlan) {
923
- recordTableAnchors(
924
- block.fragment.blockId,
925
- block.frame,
926
- block.tablePlan,
927
- pxPerTwip,
928
- tableCellRects,
929
- tableColumnEdges,
930
- tableRowEdges
931
- );
932
- }
933
- };
934
- const recordStoryRegion = (region) => {
935
- const storyKey2 = storyTargetKey(region.storyTarget);
936
- let storyMap = byRuntimeOffsetByStory.get(storyKey2);
937
- if (!storyMap) {
938
- storyMap = /* @__PURE__ */ new Map();
939
- byRuntimeOffsetByStory.set(storyKey2, storyMap);
940
- }
941
- for (const block of region.blocks) {
942
- recordBlock(block, storyMap);
943
- }
944
- };
945
- for (const page of pages) {
946
- byPageIndex.set(page.page.pageIndex, page.frame);
947
- for (const block of page.regions.body.blocks) {
948
- recordBlock(block, byRuntimeOffset);
949
- }
950
- if (page.regions.header) recordStoryRegion(page.regions.header);
951
- if (page.regions.footer) recordStoryRegion(page.regions.footer);
952
- if (page.regions.footnotes) {
953
- for (const footnote of page.regions.footnotes) {
954
- recordStoryRegion(footnote);
955
- }
956
- }
957
- }
958
- const shiftForDeltas = (offset) => {
959
- if (pendingDeltas.length === 0) return offset;
960
- return offset - sumDeltasBefore(pendingDeltas, offset);
961
- };
962
- const resolveByRuntimeOffset = (offset, story) => {
963
- const lookup = shiftForDeltas(offset);
964
- const targetMap = story && story.kind !== "main" ? byRuntimeOffsetByStory.get(storyTargetKey(story)) ?? byRuntimeOffset : byRuntimeOffset;
965
- const exact = targetMap.get(lookup);
966
- if (exact) return exact;
967
- let best = null;
968
- let bestDistance = Number.POSITIVE_INFINITY;
969
- for (const [key, rect] of targetMap) {
970
- const distance = Math.abs(key - lookup);
971
- if (distance < bestDistance) {
972
- best = rect;
973
- bestDistance = distance;
974
- }
975
- }
976
- return best;
977
- };
978
- return {
979
- byRuntimeOffset(offset, story) {
980
- return resolveByRuntimeOffset(offset, story);
981
- },
982
- byBlockId(blockId) {
983
- return byBlockId.get(blockId) ?? null;
984
- },
985
- byFragmentId(fragmentId) {
986
- return byFragmentId.get(fragmentId) ?? null;
987
- },
988
- byPageIndex(pageIndex) {
989
- return byPageIndex.get(pageIndex) ?? null;
990
- },
991
- bySelection(fromOffset, toOffset, story) {
992
- const lo = Math.min(fromOffset, toOffset);
993
- const hi = Math.max(fromOffset, toOffset);
994
- if (lo === hi) {
995
- return resolveByRuntimeOffset(lo, story);
996
- }
997
- const loShifted = shiftForDeltas(lo);
998
- const hiShifted = shiftForDeltas(hi);
999
- const targetMap = story && story.kind !== "main" ? byRuntimeOffsetByStory.get(storyTargetKey(story)) ?? byRuntimeOffset : byRuntimeOffset;
1000
- let union = null;
1001
- for (const [key, rect] of targetMap) {
1002
- if (key < loShifted || key >= hiShifted) continue;
1003
- union = unionRects(union, rect);
1004
- }
1005
- if (union) return union;
1006
- const fromRect = resolveByRuntimeOffset(lo, story);
1007
- const toRect = resolveByRuntimeOffset(hi - 1, story);
1008
- return unionRects(fromRect, toRect);
1009
- },
1010
- byTableCell(tableBlockId, rowIndex, columnIndex) {
1011
- return tableCellRects.get(`${tableBlockId}:${rowIndex}:${columnIndex}`) ?? null;
1012
- },
1013
- byTableColumnEdge(tableBlockId, columnIndex) {
1014
- return tableColumnEdges.get(`${tableBlockId}:${columnIndex}`) ?? null;
1015
- },
1016
- byTableRowEdge(tableBlockId, rowIndex) {
1017
- return tableRowEdges.get(`${tableBlockId}:${rowIndex}`) ?? null;
1018
- },
1019
- // P9 Phase A — chrome-kind resolvers sourced from the resolved
1020
- // decoration index. Empty by default (the initial frame build passes
1021
- // `EMPTY_DECORATION_INDEX` until decoration resolution runs); the
1022
- // kernel re-invokes `buildAnchorIndex` with the resolved index so the
1023
- // final anchor index carries chrome-aware lookups.
1024
- byScopeId(scopeId) {
1025
- return decorationIndex.workflow.filter((decoration) => decoration.refId === scopeId).map((decoration) => decoration.frame);
1026
- },
1027
- byCommentId(commentId) {
1028
- const match = decorationIndex.comments.find(
1029
- (decoration) => decoration.refId === commentId
1030
- );
1031
- return match?.frame ?? null;
1032
- },
1033
- byRevisionId(revisionId) {
1034
- const match = decorationIndex.revisions.find(
1035
- (decoration) => decoration.refId === revisionId
1036
- );
1037
- return match?.frame ?? null;
1038
- },
1039
- // Refactor/05 Slice 7c substrate: object-specific index. Falls back
1040
- // to `byBlockId` because the render kernel does not yet carry
1041
- // per-object metadata on anchor frames — the layout facet would
1042
- // need to emit `byObjectId` entries on the page graph. When that
1043
- // follow-up ships, populate a dedicated `byObjectIdMap` here and
1044
- // consult it before the `byBlockId` fallback. The fallback is
1045
- // correct for block-level drawings (whose object id equals their
1046
- // block id); it is `heuristic` for inline images (which share
1047
- // their block id with the enclosing paragraph). `object-handles.ts`
1048
- // tags those handles `precision: "heuristic"` accordingly.
1049
- byObjectId(objectId) {
1050
- return byBlockId.get(objectId) ?? null;
1051
- }
1052
- };
1053
- }
1054
- function recordTableAnchors(tableBlockId, blockFrame, plan, pxPerTwip, cellRects, columnEdges, rowEdges) {
1055
- if (!plan) return;
1056
- const columnCount = plan.columnsTwips.length;
1057
- if (columnCount === 0) return;
1058
- const columnLeftsPx = [blockFrame.leftPx];
1059
- for (let i = 0; i < columnCount; i += 1) {
1060
- columnLeftsPx.push(
1061
- columnLeftsPx[i] + (plan.columnsTwips[i] ?? 0) * pxPerTwip
1062
- );
1063
- }
1064
- const rowCount = Math.max(
1065
- 1,
1066
- plan.bandClasses.rows.length || plan.bandClasses.cells.reduce(
1067
- (max, c) => Math.max(max, c.rowIndex + 1),
1068
- 0
1069
- )
1070
- );
1071
- const rowHeightPx = rowCount > 0 ? blockFrame.heightPx / rowCount : blockFrame.heightPx;
1072
- const rowTopsPx = [];
1073
- for (let r = 0; r <= rowCount; r += 1) {
1074
- rowTopsPx.push(blockFrame.topPx + r * rowHeightPx);
1075
- }
1076
- for (const cell of plan.bandClasses.cells) {
1077
- const sameRow = plan.bandClasses.cells.filter((c) => c.rowIndex === cell.rowIndex);
1078
- const sorted = [...sameRow].sort((a, b) => a.columnIndex - b.columnIndex);
1079
- const idx = sorted.findIndex((c) => c === cell);
1080
- const next = sorted[idx + 1];
1081
- const columnSpan = (next?.columnIndex ?? columnCount) - cell.columnIndex;
1082
- const left = columnLeftsPx[cell.columnIndex] ?? blockFrame.leftPx;
1083
- const right = columnLeftsPx[cell.columnIndex + columnSpan] ?? blockFrame.leftPx + blockFrame.widthPx;
1084
- const top = rowTopsPx[cell.rowIndex] ?? blockFrame.topPx;
1085
- const bottom = rowTopsPx[cell.rowIndex + 1] ?? blockFrame.topPx + blockFrame.heightPx;
1086
- cellRects.set(`${tableBlockId}:${cell.rowIndex}:${cell.columnIndex}`, {
1087
- leftPx: left,
1088
- topPx: top,
1089
- widthPx: Math.max(0, right - left),
1090
- heightPx: Math.max(0, bottom - top)
1091
- });
1092
- }
1093
- for (const handle of plan.columnResizeHandles) {
1094
- const x = blockFrame.leftPx + handle.originTwips * pxPerTwip;
1095
- columnEdges.set(`${tableBlockId}:${handle.columnIndex}`, {
1096
- leftPx: x,
1097
- topPx: blockFrame.topPx,
1098
- widthPx: 0,
1099
- heightPx: handle.heightTwips * pxPerTwip
1100
- });
1101
- }
1102
- for (let r = 0; r < rowCount - 1; r += 1) {
1103
- const y = rowTopsPx[r + 1] ?? blockFrame.topPx + blockFrame.heightPx;
1104
- rowEdges.set(`${tableBlockId}:${r}`, {
1105
- leftPx: blockFrame.leftPx,
1106
- topPx: y,
1107
- widthPx: blockFrame.widthPx,
1108
- heightPx: 0
1109
- });
1110
- }
1111
- }
1112
- function unionRects(a, b) {
1113
- if (!a) return b ?? null;
1114
- if (!b) return a;
1115
- const left = Math.min(a.leftPx, b.leftPx);
1116
- const top = Math.min(a.topPx, b.topPx);
1117
- const right = Math.max(a.leftPx + a.widthPx, b.leftPx + b.widthPx);
1118
- const bottom = Math.max(a.topPx + a.heightPx, b.topPx + b.heightPx);
1119
- return {
1120
- leftPx: left,
1121
- topPx: top,
1122
- widthPx: right - left,
1123
- heightPx: bottom - top
1124
- };
1125
- }
1126
- function buildDecorationIndex(pages) {
1127
- const workflow = [];
1128
- const comments = [];
1129
- const revisions = [];
1130
- const search = [];
1131
- const locked = [];
1132
- for (const page of pages) {
1133
- for (const block of page.regions.body.blocks) {
1134
- for (const decoration of block.blockDecorations) {
1135
- switch (decoration.kind) {
1136
- case "workflow":
1137
- workflow.push(decoration);
1138
- break;
1139
- case "comment":
1140
- comments.push(decoration);
1141
- break;
1142
- case "revision":
1143
- revisions.push(decoration);
1144
- break;
1145
- case "search":
1146
- search.push(decoration);
1147
- break;
1148
- case "locked":
1149
- locked.push(decoration);
1150
- break;
1151
- }
1152
- }
1153
- }
1154
- }
1155
- return { workflow, comments, revisions, search, locked };
1156
- }
1157
- function extractRevisionFromPageId(pageId) {
1158
- const match = /^page-(\d+)-/.exec(pageId);
1159
- if (!match) return pageId;
1160
- return Number(match[1]);
1161
- }
11
+ } from "./chunk-RYMMKOFI.js";
1162
12
 
1163
13
  // src/runtime/geometry/geometry-index-queries.ts
1164
14
  function resolveHitTestFromGeometryIndex(index, point) {
@@ -1252,7 +102,7 @@ function resolveSelectionRectsFromGeometryIndex(index, range) {
1252
102
  const lineIds = unique(anchors.map((anchor) => anchor.lineId).filter(isString));
1253
103
  const lineRects = lineIds.map((lineId) => index.lines.find((line) => line.lineId === lineId)).filter(isDefined).map((line) => ({ ...line.rect, precision: "within-tolerance" }));
1254
104
  if (lineRects.length > 0) return lineRects;
1255
- return [unionRects2(anchors.map((anchor) => anchor.rect), "within-tolerance")].filter(isDefined);
105
+ return [unionRects(anchors.map((anchor) => anchor.rect), "within-tolerance")].filter(isDefined);
1256
106
  }
1257
107
  function resolveReplacementEnvelopeFromGeometryIndex(index, scopeId) {
1258
108
  const entry = index?.replacementEnvelopes.find(
@@ -1287,7 +137,7 @@ function resolveObjectHandlesFromGeometryIndex(index, objectId) {
1287
137
  (candidate) => candidate.objectId === objectId
1288
138
  );
1289
139
  if (entry) return entry.rects;
1290
- const rect = index ? unionRects2(
140
+ const rect = index ? unionRects(
1291
141
  index.slices.filter((slice) => slice.blockId === objectId).map((slice) => slice.rect),
1292
142
  "heuristic"
1293
143
  ) : null;
@@ -1409,9 +259,9 @@ function nearestTarget(targets, point) {
1409
259
  return best?.target ?? null;
1410
260
  }
1411
261
  function unionSlices(slices) {
1412
- return slices.length > 0 ? [unionRects2(slices.map((slice) => slice.rect), "within-tolerance")].filter(isDefined) : [];
262
+ return slices.length > 0 ? [unionRects(slices.map((slice) => slice.rect), "within-tolerance")].filter(isDefined) : [];
1413
263
  }
1414
- function unionRects2(rects, precision) {
264
+ function unionRects(rects, precision) {
1415
265
  if (rects.length === 0) return null;
1416
266
  let left = Infinity;
1417
267
  let top = Infinity;
@@ -4364,12 +3214,6 @@ function buildGeometryDebugEntry(inputs) {
4364
3214
  }
4365
3215
 
4366
3216
  export {
4367
- PREDICTED_LANE_COUNTERS,
4368
- startPerfProbe,
4369
- finishPerfProbe,
4370
- recordPerfSample,
4371
- incrementInvalidationCounter,
4372
- createRenderKernel,
4373
3217
  collectLineBoxesForRegion,
4374
3218
  createGeometryFacet,
4375
3219
  buildGeometryDebugEntry,