@beyondwork/docx-react-component 1.0.131 → 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 +1 -1
@@ -19,13 +19,13 @@ import {
19
19
  resolveSectionVariants,
20
20
  sectionSupportsStoryTarget,
21
21
  storyTargetKey
22
- } from "./chunk-A3GSNB4G.js";
22
+ } from "./chunk-U3UMKA7B.js";
23
23
  import {
24
24
  createSelectionSnapshot
25
25
  } from "./chunk-OYGMRRR7.js";
26
26
  import {
27
27
  collectCanonicalLayoutInputs
28
- } from "./chunk-A66ZVUAT.js";
28
+ } from "./chunk-RYMMKOFI.js";
29
29
  import {
30
30
  MAIN_STORY_TARGET,
31
31
  createDetachedAnchor,
@@ -110,6 +110,1175 @@ function createScopeTagRegistry() {
110
110
  };
111
111
  }
112
112
 
113
+ // src/runtime/telemetry/perf-probe.ts
114
+ var PREDICTED_LANE_COUNTERS = {
115
+ applied: "predictions.applied",
116
+ equivalent: "predictions.equivalent",
117
+ adjusted: "predictions.adjusted",
118
+ rejected: "predictions.rejected",
119
+ rollback: "predictions.rollback",
120
+ structuralDivergence: "predictions.structuralDivergence",
121
+ bailBeforePredict: "predictions.bailBeforePredict",
122
+ refreshSelectionOnly: "predictions.refresh.selectionOnly",
123
+ refreshLocalTextEquivalent: "predictions.refresh.localTextEquivalent",
124
+ refreshSurfaceOnly: "predictions.refresh.surfaceOnly",
125
+ refreshFullProjection: "predictions.refresh.fullProjection",
126
+ refreshBlocked: "predictions.refresh.blocked"
127
+ };
128
+ function startPerfProbe(kind) {
129
+ const state = getEnabledState();
130
+ if (!state) {
131
+ return null;
132
+ }
133
+ const token = `${kind}-${state.nextToken ?? 0}`;
134
+ state.nextToken = (state.nextToken ?? 0) + 1;
135
+ state.pending ??= {};
136
+ state.pending[token] = {
137
+ kind,
138
+ startedAt: performance.now()
139
+ };
140
+ return token;
141
+ }
142
+ function finishPerfProbe(token) {
143
+ if (!token) {
144
+ return null;
145
+ }
146
+ const state = getEnabledState();
147
+ if (!state?.pending?.[token]) {
148
+ return null;
149
+ }
150
+ const pending = state.pending[token];
151
+ delete state.pending[token];
152
+ const sample = {
153
+ token,
154
+ kind: pending.kind,
155
+ durationMs: performance.now() - pending.startedAt,
156
+ recordedAt: Date.now()
157
+ };
158
+ pushSample(state, sample);
159
+ return sample;
160
+ }
161
+ function recordPerfSample(kind, durationMs = 0) {
162
+ const state = getEnabledState();
163
+ if (!state) {
164
+ return null;
165
+ }
166
+ const token = `${kind}-${state.nextToken ?? 0}`;
167
+ state.nextToken = (state.nextToken ?? 0) + 1;
168
+ const sample = {
169
+ token,
170
+ kind,
171
+ durationMs,
172
+ recordedAt: Date.now()
173
+ };
174
+ pushSample(state, sample);
175
+ return sample;
176
+ }
177
+ function incrementInvalidationCounter(counter, amount = 1) {
178
+ const state = getEnabledState();
179
+ if (!state) {
180
+ return 0;
181
+ }
182
+ state.invalidationCounts ??= {};
183
+ state.invalidationCounts[counter] = (state.invalidationCounts[counter] ?? 0) + amount;
184
+ return state.invalidationCounts[counter];
185
+ }
186
+ function getEnabledState() {
187
+ if (typeof window === "undefined") {
188
+ return null;
189
+ }
190
+ const state = window.__DOCX_REACT_PERF_PROBE__;
191
+ if (!state?.enabled) {
192
+ return null;
193
+ }
194
+ return state;
195
+ }
196
+ function pushSample(state, sample) {
197
+ state.samples ??= [];
198
+ state.samples.push(sample);
199
+ const maxSamples = state.maxSamples ?? 20;
200
+ if (state.samples.length > maxSamples) {
201
+ state.samples.splice(0, state.samples.length - maxSamples);
202
+ }
203
+ }
204
+
205
+ // src/runtime/render/decoration-resolver.ts
206
+ function resolveDecorationIndex(input) {
207
+ const workflow = [];
208
+ const comments = [];
209
+ const revisions = [];
210
+ const search = [];
211
+ const locked = [];
212
+ if (input.workflowSegments) {
213
+ for (const segment of input.workflowSegments) {
214
+ const frame = input.anchorIndex.bySelection(
215
+ segment.fromOffset,
216
+ segment.toOffset
217
+ );
218
+ if (!frame) continue;
219
+ workflow.push({
220
+ kind: "workflow",
221
+ refId: segment.scopeId,
222
+ frame
223
+ });
224
+ }
225
+ }
226
+ if (input.comments) {
227
+ for (const thread of input.comments.threads) {
228
+ const frame = resolveRange(
229
+ input.anchorIndex,
230
+ thread.from,
231
+ thread.to
232
+ );
233
+ if (!frame) continue;
234
+ comments.push({
235
+ kind: "comment",
236
+ refId: thread.commentId,
237
+ frame
238
+ });
239
+ void asCommentThread(thread);
240
+ }
241
+ }
242
+ if (input.revisions) {
243
+ for (const revision of input.revisions.revisions) {
244
+ const frame = resolveRange(
245
+ input.anchorIndex,
246
+ revision.from,
247
+ revision.to
248
+ );
249
+ if (!frame) continue;
250
+ revisions.push({
251
+ kind: "revision",
252
+ refId: revision.revisionId,
253
+ frame
254
+ });
255
+ void asRevisionEntry(revision);
256
+ }
257
+ }
258
+ if (input.searchMatches) {
259
+ for (const match of input.searchMatches) {
260
+ const frame = resolveRange(input.anchorIndex, match.from, match.to);
261
+ if (!frame) continue;
262
+ search.push({
263
+ kind: "search",
264
+ refId: match.matchId,
265
+ frame
266
+ });
267
+ }
268
+ }
269
+ if (input.lockedRanges) {
270
+ for (const lock of input.lockedRanges) {
271
+ const frame = resolveRange(input.anchorIndex, lock.from, lock.to);
272
+ if (!frame) continue;
273
+ locked.push({
274
+ kind: "locked",
275
+ refId: lock.lockId,
276
+ frame
277
+ });
278
+ }
279
+ }
280
+ return { workflow, comments, revisions, search, locked };
281
+ }
282
+ function resolveRange(anchorIndex, from, to) {
283
+ if (from >= to) {
284
+ return anchorIndex.byRuntimeOffset(from);
285
+ }
286
+ return anchorIndex.bySelection(from, to);
287
+ }
288
+ function asCommentThread(thread) {
289
+ return thread;
290
+ }
291
+ function asRevisionEntry(entry) {
292
+ return entry;
293
+ }
294
+
295
+ // src/runtime/render/block-fragment-projection.ts
296
+ function classifyBlockKind(blockId) {
297
+ if (blockId.startsWith("paragraph")) return "paragraph";
298
+ if (blockId.startsWith("table")) return "table";
299
+ if (blockId.startsWith("placeholder-culled-")) return "opaque";
300
+ if (blockId.startsWith("opaque")) return "opaque";
301
+ if (blockId.startsWith("section-break")) return "opaque";
302
+ if (blockId.startsWith("sdt")) return "opaque";
303
+ if (blockId.startsWith("custom-xml")) return "opaque";
304
+ if (blockId.startsWith("alt-chunk")) return "opaque";
305
+ if (blockId.startsWith("synthetic")) return "synthetic";
306
+ return "paragraph";
307
+ }
308
+
309
+ // src/runtime/render/render-frame-diff.ts
310
+ function diffRenderFrames(prev, next) {
311
+ if (!prev) {
312
+ return {
313
+ addedPages: next.pages.map((p) => p.page.pageIndex),
314
+ removedPages: [],
315
+ unchangedPages: [],
316
+ changedPages: []
317
+ };
318
+ }
319
+ const prevByIndex = /* @__PURE__ */ new Map();
320
+ for (const page of prev.pages) {
321
+ prevByIndex.set(page.page.pageIndex, page);
322
+ }
323
+ const nextIndices = /* @__PURE__ */ new Set();
324
+ for (const page of next.pages) {
325
+ nextIndices.add(page.page.pageIndex);
326
+ }
327
+ const addedPages = [];
328
+ const removedPages = [];
329
+ const unchangedPages = [];
330
+ const changedPages = [];
331
+ for (const nextPage of next.pages) {
332
+ const pageIndex = nextPage.page.pageIndex;
333
+ const prevPage = prevByIndex.get(pageIndex);
334
+ if (!prevPage) {
335
+ addedPages.push(pageIndex);
336
+ continue;
337
+ }
338
+ const regions = diffPage(prevPage, nextPage, prev.decorationIndex, next.decorationIndex);
339
+ const frameChanged = !rectEquals(prevPage.frame, nextPage.frame);
340
+ const reservationsChanged = !reservationsEqual(
341
+ prevPage.chromeReservations,
342
+ nextPage.chromeReservations
343
+ );
344
+ if (regions.length === 0 && !frameChanged && !reservationsChanged) {
345
+ unchangedPages.push(pageIndex);
346
+ } else {
347
+ changedPages.push({
348
+ pageIndex,
349
+ regions,
350
+ ...frameChanged ? { pageFrameChanged: true } : {}
351
+ });
352
+ }
353
+ }
354
+ for (const prevPage of prev.pages) {
355
+ if (!nextIndices.has(prevPage.page.pageIndex)) {
356
+ removedPages.push(prevPage.page.pageIndex);
357
+ }
358
+ }
359
+ return { addedPages, removedPages, unchangedPages, changedPages };
360
+ }
361
+ function createPagePatchPlan(prev, next, diff = diffRenderFrames(prev, next), options = {}) {
362
+ const prevByIndex = indexPagesByIndex(prev?.pages ?? []);
363
+ const nextByIndex = indexPagesByIndex(next.pages);
364
+ const addedPages = diff.addedPages.map(
365
+ (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
366
+ );
367
+ const removedPages = diff.removedPages.map(
368
+ (pageIndex) => pageIdForIndex(prevByIndex, pageIndex)
369
+ );
370
+ const unchangedPages = diff.unchangedPages.map(
371
+ (pageIndex) => pageIdForIndex(nextByIndex, pageIndex)
372
+ );
373
+ const changedPages = diff.changedPages.map(
374
+ (entry) => createPagePatchEntry(entry, pageIdForIndex(nextByIndex, entry.pageIndex), options)
375
+ );
376
+ return {
377
+ layoutRevision: options.layoutRevision ?? next.revision,
378
+ geometryRevision: options.geometryRevision ?? next.revision,
379
+ addedPages,
380
+ removedPages,
381
+ unchangedPages,
382
+ changedPages,
383
+ mountChanges: resolveMountChanges({
384
+ addedPages,
385
+ removedPages,
386
+ mountedPageIds: options.mountedPageIds,
387
+ requestedMountPageIds: options.requestedMountPageIds
388
+ })
389
+ };
390
+ }
391
+ function createPagePatchEntry(entry, pageId, options) {
392
+ const regionChanges = entry.regions.map((region) => region.kind);
393
+ const fragmentChanges = uniqueStrings(
394
+ entry.regions.flatMap((region) => region.changedBlockIds)
395
+ );
396
+ const overlayLaneChanges = !entry.pageFrameChanged && entry.regions.length === 0 ? ["chrome-reservations"] : [];
397
+ return {
398
+ pageId,
399
+ pageIndex: entry.pageIndex,
400
+ frameChanged: entry.pageFrameChanged === true,
401
+ regionChanges,
402
+ fragmentChanges,
403
+ lineBoxChanges: fragmentChanges,
404
+ overlayLaneChanges,
405
+ reason: options.reason ?? (overlayLaneChanges.length > 0 ? "overlay" : "layout")
406
+ };
407
+ }
408
+ function resolveMountChanges(input) {
409
+ if (!input.mountedPageIds || !input.requestedMountPageIds) {
410
+ return {
411
+ mountPageIds: input.addedPages,
412
+ unmountPageIds: input.removedPages
413
+ };
414
+ }
415
+ const mounted = new Set(input.mountedPageIds);
416
+ const requested = new Set(input.requestedMountPageIds);
417
+ return {
418
+ mountPageIds: input.requestedMountPageIds.filter((pageId) => !mounted.has(pageId)),
419
+ unmountPageIds: input.mountedPageIds.filter((pageId) => !requested.has(pageId))
420
+ };
421
+ }
422
+ function indexPagesByIndex(pages) {
423
+ return new Map(pages.map((page) => [page.page.pageIndex, page]));
424
+ }
425
+ function pageIdForIndex(pages, pageIndex) {
426
+ return pages.get(pageIndex)?.page.pageId ?? `page:${pageIndex}`;
427
+ }
428
+ function uniqueStrings(values) {
429
+ return [...new Set(values)];
430
+ }
431
+ function diffPage(prev, next, prevIndex, nextIndex) {
432
+ const changed = [];
433
+ const bodyChanges = diffRegion(prev.regions.body, next.regions.body, prevIndex, nextIndex);
434
+ if (bodyChanges.length > 0) {
435
+ changed.push({ kind: "body", changedBlockIds: bodyChanges });
436
+ }
437
+ const headerChanges = diffOptionalRegion(
438
+ prev.regions.header,
439
+ next.regions.header,
440
+ prevIndex,
441
+ nextIndex
442
+ );
443
+ if (headerChanges.length > 0) {
444
+ changed.push({ kind: "header", changedBlockIds: headerChanges });
445
+ }
446
+ const footerChanges = diffOptionalRegion(
447
+ prev.regions.footer,
448
+ next.regions.footer,
449
+ prevIndex,
450
+ nextIndex
451
+ );
452
+ if (footerChanges.length > 0) {
453
+ changed.push({ kind: "footer", changedBlockIds: footerChanges });
454
+ }
455
+ const prevFoot = prev.regions.footnotes ?? [];
456
+ const nextFoot = next.regions.footnotes ?? [];
457
+ if (prevFoot.length !== nextFoot.length) {
458
+ changed.push({ kind: "footnote-area", changedBlockIds: ["<count-changed>"] });
459
+ } else {
460
+ for (let i = 0; i < prevFoot.length; i += 1) {
461
+ const fChanges = diffRegion(prevFoot[i], nextFoot[i], prevIndex, nextIndex);
462
+ if (fChanges.length > 0) {
463
+ changed.push({ kind: "footnote-area", changedBlockIds: fChanges });
464
+ }
465
+ }
466
+ }
467
+ return changed;
468
+ }
469
+ function diffOptionalRegion(prev, next, prevIndex, nextIndex) {
470
+ if (!prev && !next) return [];
471
+ if (!prev && next) return ["<added>"];
472
+ if (prev && !next) return ["<removed>"];
473
+ return diffRegion(prev, next, prevIndex, nextIndex);
474
+ }
475
+ function diffRegion(prev, next, prevIndex, nextIndex) {
476
+ const changed = [];
477
+ if (!rectEquals(prev.frame, next.frame)) {
478
+ changed.push("<region-frame>");
479
+ }
480
+ const prevBlocks = /* @__PURE__ */ new Map();
481
+ for (const block of prev.blocks) {
482
+ prevBlocks.set(block.fragment.blockId, block);
483
+ }
484
+ const nextIds = /* @__PURE__ */ new Set();
485
+ for (const block of next.blocks) {
486
+ nextIds.add(block.fragment.blockId);
487
+ const prevBlock = prevBlocks.get(block.fragment.blockId);
488
+ if (!prevBlock) {
489
+ changed.push(block.fragment.blockId);
490
+ continue;
491
+ }
492
+ if (!blocksStructurallyEqual(prevBlock, block, prevIndex, nextIndex)) {
493
+ changed.push(block.fragment.blockId);
494
+ }
495
+ }
496
+ for (const blockId of prevBlocks.keys()) {
497
+ if (!nextIds.has(blockId)) changed.push(blockId);
498
+ }
499
+ return changed;
500
+ }
501
+ function blocksStructurallyEqual(a, b, aIndex, bIndex) {
502
+ if (a.kind !== b.kind) return false;
503
+ if (a.fragment.regionKind !== b.fragment.regionKind) return false;
504
+ if (a.fragment.from !== b.fragment.from) return false;
505
+ if (a.fragment.to !== b.fragment.to) return false;
506
+ if (!rectEquals(a.frame, b.frame)) return false;
507
+ if (a.lines.length !== b.lines.length) return false;
508
+ for (let i = 0; i < a.lines.length; i += 1) {
509
+ if (!rectEquals(a.lines[i].frame, b.lines[i].frame)) return false;
510
+ }
511
+ const aHash = decorationHashForBlock(a.frame, aIndex);
512
+ const bHash = decorationHashForBlock(b.frame, bIndex);
513
+ if (aHash !== bHash) return false;
514
+ return true;
515
+ }
516
+ function decorationHashForBlock(blockFrame, index) {
517
+ const tokens = [];
518
+ for (const lane of [index.workflow, index.comments, index.revisions, index.search, index.locked]) {
519
+ for (const entry of lane) {
520
+ if (rectIntersects(entry.frame, blockFrame)) {
521
+ tokens.push(`${entry.kind}:${entry.refId}`);
522
+ }
523
+ }
524
+ }
525
+ tokens.sort();
526
+ return tokens.join("|");
527
+ }
528
+ function reservationsEqual(a, b) {
529
+ return a.railLaneTwips === b.railLaneTwips && a.balloonLaneTwips === b.balloonLaneTwips && a.footnoteAreaTwips === b.footnoteAreaTwips && a.pageFrameWidthPx === b.pageFrameWidthPx && a.pageFrameHeightPx === b.pageFrameHeightPx;
530
+ }
531
+ var RECT_EPS = 0.1;
532
+ function rectEquals(a, b) {
533
+ 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;
534
+ }
535
+ function rectIntersects(a, b) {
536
+ 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);
537
+ }
538
+
539
+ // src/runtime/render/render-frame-types.ts
540
+ var DEFAULT_PX_PER_TWIP = 96 / 1440;
541
+ var PAGE_STACK_GAP_PX = 48;
542
+ function resolveDefaultZoom(input = {}) {
543
+ return {
544
+ pxPerTwip: input.pxPerTwip ?? DEFAULT_PX_PER_TWIP,
545
+ viewportWidthPx: input.viewportWidthPx ?? 900,
546
+ fitMode: input.fitMode ?? "fixed"
547
+ };
548
+ }
549
+ var EMPTY_DECORATION_INDEX = Object.freeze({
550
+ workflow: Object.freeze([]),
551
+ comments: Object.freeze([]),
552
+ revisions: Object.freeze([]),
553
+ search: Object.freeze([]),
554
+ locked: Object.freeze([])
555
+ });
556
+ function defaultChromeReservations(layout, zoom) {
557
+ return {
558
+ railLaneTwips: 360,
559
+ balloonLaneTwips: 2160,
560
+ footnoteAreaTwips: 0,
561
+ pageFrameWidthPx: layout.pageWidth * zoom.pxPerTwip,
562
+ pageFrameHeightPx: layout.pageHeight * zoom.pxPerTwip
563
+ };
564
+ }
565
+
566
+ // src/runtime/render/render-kernel.ts
567
+ function sumDeltasBefore(deltas, runtimeOffset) {
568
+ let total = 0;
569
+ for (const d of deltas) {
570
+ if (d.fromRuntime <= runtimeOffset) total += d.delta;
571
+ }
572
+ return total;
573
+ }
574
+ function createRenderKernel(input) {
575
+ const { facet } = input;
576
+ const getActiveStory = input.getActiveStory ?? (() => MAIN_STORY_TARGET);
577
+ let zoom = input.initialZoom ?? resolveDefaultZoom();
578
+ let cache = null;
579
+ let lastEmittedFrame = null;
580
+ let diCacheKey = null;
581
+ let diCacheValue = null;
582
+ const listeners = /* @__PURE__ */ new Set();
583
+ const unsubscribeFacet = facet.subscribe((event) => {
584
+ if (event.kind === "layout_recomputed" || event.kind === "incremental_relayout" || event.kind === "measurement_backend_ready" || event.kind === "zoom_changed") {
585
+ cache = null;
586
+ }
587
+ });
588
+ void unsubscribeFacet;
589
+ function emit(event) {
590
+ for (const listener of listeners) {
591
+ try {
592
+ listener(event);
593
+ } catch {
594
+ }
595
+ }
596
+ }
597
+ function buildFrame(options) {
598
+ const t0 = typeof performance !== "undefined" ? performance.now() : 0;
599
+ const activeStory = options?.story ?? getActiveStory();
600
+ const measurementFidelity = facet.getMeasurementFidelity();
601
+ const rawPages = facet.getPages();
602
+ const pageRange = options?.pageRange;
603
+ const filteredPages = pageRange ? rawPages.filter(
604
+ (p) => p.pageIndex >= pageRange.fromPageIndex && p.pageIndex <= pageRange.toPageIndex
605
+ ) : rawPages;
606
+ let y = 0;
607
+ const renderPages = [];
608
+ for (const page of filteredPages) {
609
+ const renderPage = buildPage(page, y, zoom, activeStory, facet);
610
+ renderPages.push(renderPage);
611
+ y += renderPage.frame.heightPx + PAGE_STACK_GAP_PX;
612
+ }
613
+ const pendingDeltas = input.getPendingOpDeltas?.() ?? [];
614
+ const baseAnchorIndex = buildAnchorIndex(
615
+ renderPages,
616
+ pendingDeltas,
617
+ zoom.pxPerTwip
618
+ );
619
+ const revision = filteredPages[0] ? Number(extractRevisionFromPageId(filteredPages[0].pageId)) : 0;
620
+ const includeDecorations = options?.includeDecorations ?? true;
621
+ const sources = input.getDecorationSources?.();
622
+ 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);
623
+ const newDIKey = {
624
+ revision: Number.isFinite(revision) ? revision : 0,
625
+ activeStoryKind: activeStory.kind,
626
+ zoomPxPerTwip: zoom.pxPerTwip,
627
+ workflowSegments: sources?.workflowSegments,
628
+ comments: sources?.comments,
629
+ revisions: sources?.revisions,
630
+ searchMatches: sources?.searchMatches,
631
+ lockedRanges: sources?.lockedRanges
632
+ };
633
+ 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;
634
+ let decorationIndex;
635
+ if (!includeDecorations) {
636
+ decorationIndex = EMPTY_DECORATION_INDEX;
637
+ } else if (hasSources) {
638
+ if (diCacheHit) {
639
+ decorationIndex = diCacheValue;
640
+ } else {
641
+ decorationIndex = resolveDecorationIndex({ anchorIndex: baseAnchorIndex, ...sources });
642
+ diCacheKey = newDIKey;
643
+ diCacheValue = decorationIndex;
644
+ }
645
+ } else {
646
+ decorationIndex = buildDecorationIndex(renderPages);
647
+ }
648
+ const anchorIndex = buildAnchorIndex(
649
+ renderPages,
650
+ pendingDeltas,
651
+ zoom.pxPerTwip,
652
+ decorationIndex
653
+ );
654
+ const frame = {
655
+ revision: Number.isFinite(revision) ? revision : 0,
656
+ measurementFidelity,
657
+ activeStory,
658
+ zoom: { ...zoom },
659
+ pages: renderPages,
660
+ decorationIndex,
661
+ anchorIndex
662
+ };
663
+ if (t0 > 0) recordPerfSample("render.frame_build", performance.now() - t0);
664
+ return frame;
665
+ }
666
+ return {
667
+ getRenderFrame(options) {
668
+ const rebuild = options !== void 0 || cache === null;
669
+ if (!rebuild && cache) {
670
+ return cache.frame;
671
+ }
672
+ const frame = buildFrame(options);
673
+ if (options === void 0) {
674
+ cache = { revision: frame.revision, frame };
675
+ emit({ kind: "frame_built", revision: frame.revision, reason: "full" });
676
+ const diffT0 = typeof performance !== "undefined" ? performance.now() : 0;
677
+ const diff = diffRenderFrames(lastEmittedFrame, frame);
678
+ const patchPlan = createPagePatchPlan(lastEmittedFrame, frame, diff);
679
+ recordPagePatchPlanTelemetry(patchPlan);
680
+ if (diffT0 > 0) {
681
+ recordPerfSample("render.frame_diff", performance.now() - diffT0);
682
+ }
683
+ emit({ kind: "frame_diff", revision: frame.revision, diff, patchPlan });
684
+ lastEmittedFrame = frame;
685
+ }
686
+ return frame;
687
+ },
688
+ getZoom() {
689
+ return { ...zoom };
690
+ },
691
+ setZoom(next) {
692
+ zoom = { ...next };
693
+ cache = null;
694
+ },
695
+ subscribe(listener) {
696
+ listeners.add(listener);
697
+ return () => {
698
+ listeners.delete(listener);
699
+ };
700
+ },
701
+ invalidate() {
702
+ cache = null;
703
+ }
704
+ };
705
+ }
706
+ function recordPagePatchPlanTelemetry(plan) {
707
+ incrementInvalidationCounter(
708
+ "pageRender.patch.addedPages",
709
+ plan.addedPages.length
710
+ );
711
+ incrementInvalidationCounter(
712
+ "pageRender.patch.removedPages",
713
+ plan.removedPages.length
714
+ );
715
+ incrementInvalidationCounter(
716
+ "pageRender.patch.unchangedPages",
717
+ plan.unchangedPages.length
718
+ );
719
+ incrementInvalidationCounter(
720
+ "pageRender.patch.changedFragments",
721
+ plan.changedPages.reduce(
722
+ (total, page) => total + page.fragmentChanges.length,
723
+ 0
724
+ )
725
+ );
726
+ incrementInvalidationCounter(
727
+ "pageRender.patch.mountedPages",
728
+ plan.mountChanges.mountPageIds.length
729
+ );
730
+ incrementInvalidationCounter(
731
+ "pageRender.patch.unmountedPages",
732
+ plan.mountChanges.unmountPageIds.length
733
+ );
734
+ }
735
+ function buildPage(page, topPx, zoom, activeStory, facet) {
736
+ const layout = page.layout;
737
+ const widthPx = layout.pageWidth * zoom.pxPerTwip;
738
+ const heightPx = layout.pageHeight * zoom.pxPerTwip;
739
+ const frame = {
740
+ leftPx: 0,
741
+ topPx,
742
+ widthPx,
743
+ heightPx
744
+ };
745
+ const bodyRegion = buildBodyRegion(
746
+ page,
747
+ topPx,
748
+ zoom,
749
+ activeStory,
750
+ facet
751
+ );
752
+ const regions = {
753
+ body: bodyRegion
754
+ };
755
+ if (page.stories.header) {
756
+ regions.header = buildHeaderFooterRegion(
757
+ page,
758
+ topPx,
759
+ zoom,
760
+ "header",
761
+ page.stories.header,
762
+ facet
763
+ );
764
+ }
765
+ if (page.stories.footer) {
766
+ regions.footer = buildHeaderFooterRegion(
767
+ page,
768
+ topPx,
769
+ zoom,
770
+ "footer",
771
+ page.stories.footer,
772
+ facet
773
+ );
774
+ }
775
+ const footnoteRegions = buildFootnoteRegions(page, topPx, zoom, facet);
776
+ if (footnoteRegions.length > 0) {
777
+ regions.footnotes = footnoteRegions;
778
+ }
779
+ const chromeReservations = {
780
+ ...defaultChromeReservations(layout, zoom)
781
+ };
782
+ return {
783
+ page,
784
+ frame,
785
+ regions,
786
+ chromeReservations
787
+ };
788
+ }
789
+ function buildBodyRegion(page, pageTopPx, zoom, activeStory, facet) {
790
+ const layout = page.layout;
791
+ const bodyLeftTwips = layout.marginLeft;
792
+ const bodyTopTwips = layout.marginTop;
793
+ const bodyWidthTwips = page.regions.body.widthTwips;
794
+ const bodyHeightTwips = page.regions.body.heightTwips;
795
+ const regionFrame = {
796
+ leftPx: bodyLeftTwips * zoom.pxPerTwip,
797
+ topPx: pageTopPx + bodyTopTwips * zoom.pxPerTwip,
798
+ widthPx: bodyWidthTwips * zoom.pxPerTwip,
799
+ heightPx: bodyHeightTwips * zoom.pxPerTwip
800
+ };
801
+ const fragments = facet.getFragmentsForPage(page.pageIndex);
802
+ const bodyLineBoxes = facet.getLineBoxes(page.pageIndex, { region: "body" });
803
+ const blocks = [];
804
+ let blockY = regionFrame.topPx;
805
+ const totalFragmentHeight = fragments.reduce(
806
+ (acc, fragment) => acc + Math.max(0, fragment.heightTwips),
807
+ 0
808
+ );
809
+ for (const fragment of fragments) {
810
+ if (fragment.regionKind !== "body") continue;
811
+ const fragmentHeightTwips = fragment.heightTwips > 0 ? fragment.heightTwips : totalFragmentHeight === 0 ? bodyHeightTwips / Math.max(1, fragments.length) : 0;
812
+ const blockHeightPx = fragmentHeightTwips * zoom.pxPerTwip;
813
+ const fallbackBlockFrame = {
814
+ leftPx: regionFrame.leftPx,
815
+ topPx: blockY,
816
+ widthPx: regionFrame.widthPx,
817
+ heightPx: blockHeightPx
818
+ };
819
+ const blockLines = bodyLineBoxes.filter((box) => box.fragmentId === fragment.fragmentId).map((box) => {
820
+ const lineFrame = lineFrameFromPublicBox(
821
+ box,
822
+ regionFrame,
823
+ pageTopPx,
824
+ bodyTopTwips,
825
+ zoom
826
+ );
827
+ const anchors = [
828
+ {
829
+ runtimeOffset: fragment.from,
830
+ frame: lineFrame,
831
+ fragmentId: fragment.fragmentId,
832
+ blockId: fragment.blockId
833
+ }
834
+ ];
835
+ return {
836
+ line: box,
837
+ frame: lineFrame,
838
+ anchors
839
+ };
840
+ });
841
+ const kind = classifyBlockKind(fragment.blockId);
842
+ const blockFrame = blockFrameFromLineFacts(
843
+ fallbackBlockFrame,
844
+ kind,
845
+ blockLines
846
+ );
847
+ const tablePlan = kind === "table" ? facet.getTableRenderPlan(fragment.blockId, page.pageIndex) : void 0;
848
+ blocks.push({
849
+ fragment,
850
+ frame: blockFrame,
851
+ kind,
852
+ lines: blockLines,
853
+ blockDecorations: [],
854
+ ...tablePlan !== void 0 ? { tablePlan } : {}
855
+ });
856
+ blockY = Math.max(blockY + blockHeightPx, blockFrame.topPx + blockFrame.heightPx);
857
+ }
858
+ return {
859
+ storyTarget: activeStory,
860
+ region: page.regions.body,
861
+ frame: regionFrame,
862
+ blocks
863
+ };
864
+ }
865
+ function lineFrameFromPublicBox(box, regionFrame, pageTopPx, bodyTopTwips, zoom) {
866
+ if (box.rectTwips) {
867
+ return projectPageTwipsRectToFrame(box.rectTwips, pageTopPx, zoom);
868
+ }
869
+ const lineTopPx = pageTopPx + (bodyTopTwips + box.baselineTwips) * zoom.pxPerTwip;
870
+ return {
871
+ leftPx: regionFrame.leftPx,
872
+ topPx: lineTopPx,
873
+ widthPx: Math.min(
874
+ regionFrame.widthPx,
875
+ box.widthTwips * zoom.pxPerTwip
876
+ ),
877
+ heightPx: box.heightTwips * zoom.pxPerTwip
878
+ };
879
+ }
880
+ function projectPageTwipsRectToFrame(rect2, pageTopPx, zoom) {
881
+ return {
882
+ leftPx: rect2.xTwips * zoom.pxPerTwip,
883
+ topPx: pageTopPx + rect2.yTwips * zoom.pxPerTwip,
884
+ widthPx: rect2.widthTwips * zoom.pxPerTwip,
885
+ heightPx: rect2.heightTwips * zoom.pxPerTwip
886
+ };
887
+ }
888
+ function blockFrameFromLineFacts(fallback, kind, lines) {
889
+ const union = unionRenderLineFrames(lines);
890
+ if (!union) return fallback;
891
+ if (kind === "paragraph") return union;
892
+ if (fallback.widthPx <= 0 || fallback.heightPx <= 0) return union;
893
+ return fallback;
894
+ }
895
+ function unionRenderLineFrames(lines) {
896
+ let left = Number.POSITIVE_INFINITY;
897
+ let top = Number.POSITIVE_INFINITY;
898
+ let right = Number.NEGATIVE_INFINITY;
899
+ let bottom = Number.NEGATIVE_INFINITY;
900
+ for (const line of lines) {
901
+ if (line.frame.widthPx <= 0 || line.frame.heightPx <= 0) continue;
902
+ left = Math.min(left, line.frame.leftPx);
903
+ top = Math.min(top, line.frame.topPx);
904
+ right = Math.max(right, line.frame.leftPx + line.frame.widthPx);
905
+ bottom = Math.max(bottom, line.frame.topPx + line.frame.heightPx);
906
+ }
907
+ if (!Number.isFinite(left) || !Number.isFinite(top)) return null;
908
+ return {
909
+ leftPx: left,
910
+ topPx: top,
911
+ widthPx: Math.max(0, right - left),
912
+ heightPx: Math.max(0, bottom - top)
913
+ };
914
+ }
915
+ function buildHeaderFooterRegion(page, pageTopPx, zoom, kind, storyTarget, facet) {
916
+ const layout = page.layout;
917
+ const fallbackWidthTwips = layout.pageWidth - layout.marginLeft - layout.marginRight;
918
+ const fallbackTopTwips = kind === "header" ? layout.headerMargin ?? 720 : layout.pageHeight - layout.marginBottom;
919
+ const fallbackHeightTwips = kind === "header" ? Math.max(0, layout.marginTop - (layout.headerMargin ?? 720)) : Math.max(0, layout.marginBottom - (layout.footerMargin ?? 720));
920
+ const region = (kind === "header" ? page.regions.header : page.regions.footer) ?? {
921
+ kind,
922
+ originTwips: fallbackTopTwips,
923
+ widthTwips: fallbackWidthTwips,
924
+ heightTwips: fallbackHeightTwips,
925
+ fragmentCount: 0
926
+ };
927
+ const frame = {
928
+ leftPx: layout.marginLeft * zoom.pxPerTwip,
929
+ topPx: pageTopPx + region.originTwips * zoom.pxPerTwip,
930
+ widthPx: region.widthTwips * zoom.pxPerTwip,
931
+ heightPx: region.heightTwips * zoom.pxPerTwip
932
+ };
933
+ const regionBlocks = facet.getStoryBlocksForRegion(page.pageIndex, kind);
934
+ const blocks = projectRegionBlocks(
935
+ regionBlocks,
936
+ frame,
937
+ zoom.pxPerTwip,
938
+ page.pageId,
939
+ page.pageIndex,
940
+ kind
941
+ );
942
+ return {
943
+ storyTarget,
944
+ region,
945
+ frame,
946
+ blocks
947
+ };
948
+ }
949
+ function buildFootnoteRegions(page, pageTopPx, zoom, facet) {
950
+ const footnoteRegions = page.regions.footnotes;
951
+ if (!footnoteRegions || footnoteRegions.length === 0) return [];
952
+ const regionBlocks = facet.getStoryBlocksForRegion(
953
+ page.pageIndex,
954
+ "footnote-area"
955
+ );
956
+ if (regionBlocks.length === 0) return [];
957
+ const results = [];
958
+ let cursor = 0;
959
+ for (const region of footnoteRegions) {
960
+ const frame = {
961
+ leftPx: page.layout.marginLeft * zoom.pxPerTwip,
962
+ topPx: pageTopPx + region.originTwips * zoom.pxPerTwip,
963
+ widthPx: region.widthTwips * zoom.pxPerTwip,
964
+ heightPx: region.heightTwips * zoom.pxPerTwip
965
+ };
966
+ const blocksForThisRegion = footnoteRegions.length === 1 ? regionBlocks : regionBlocks.slice(cursor, cursor + region.fragmentCount);
967
+ cursor += region.fragmentCount;
968
+ const blocks = projectRegionBlocks(
969
+ blocksForThisRegion,
970
+ frame,
971
+ zoom.pxPerTwip,
972
+ page.pageId,
973
+ page.pageIndex,
974
+ "footnote-area"
975
+ );
976
+ const firstNote = page.noteAllocations.find(
977
+ (alloc) => alloc.noteKind === "footnote"
978
+ );
979
+ const storyTarget = firstNote ? { kind: "footnote", noteId: firstNote.noteId } : MAIN_STORY_TARGET;
980
+ results.push({
981
+ storyTarget,
982
+ region,
983
+ frame,
984
+ blocks
985
+ });
986
+ }
987
+ return results;
988
+ }
989
+ function projectRegionBlocks(regionBlocks, regionFrame, pxPerTwip, pageId, pageIndex, regionKind) {
990
+ const blocks = [];
991
+ let y = regionFrame.topPx;
992
+ for (let i = 0; i < regionBlocks.length; i += 1) {
993
+ const regionBlock = regionBlocks[i];
994
+ const blockHeightPx = Math.max(0, regionBlock.heightTwips) * pxPerTwip;
995
+ const blockFrame = {
996
+ leftPx: regionFrame.leftPx,
997
+ topPx: y,
998
+ widthPx: regionFrame.widthPx,
999
+ heightPx: blockHeightPx
1000
+ };
1001
+ const fragment = {
1002
+ fragmentId: regionBlock.fragmentId,
1003
+ blockId: regionBlock.blockId,
1004
+ pageId,
1005
+ pageIndex,
1006
+ regionKind,
1007
+ from: regionBlock.runtimeFromOffset,
1008
+ to: regionBlock.runtimeToOffset,
1009
+ heightTwips: regionBlock.heightTwips,
1010
+ orderInRegion: i
1011
+ };
1012
+ blocks.push({
1013
+ fragment,
1014
+ frame: blockFrame,
1015
+ kind: classifyBlockKind(regionBlock.blockId),
1016
+ lines: [],
1017
+ blockDecorations: []
1018
+ });
1019
+ y += blockHeightPx;
1020
+ }
1021
+ return blocks;
1022
+ }
1023
+ function buildAnchorIndex(pages, pendingDeltas = [], pxPerTwip = 1, decorationIndex = EMPTY_DECORATION_INDEX) {
1024
+ const byRuntimeOffset = /* @__PURE__ */ new Map();
1025
+ const byRuntimeOffsetByStory = /* @__PURE__ */ new Map();
1026
+ const byFragmentId = /* @__PURE__ */ new Map();
1027
+ const byBlockId = /* @__PURE__ */ new Map();
1028
+ const byPageIndex = /* @__PURE__ */ new Map();
1029
+ const tableCellRects = /* @__PURE__ */ new Map();
1030
+ const tableColumnEdges = /* @__PURE__ */ new Map();
1031
+ const tableRowEdges = /* @__PURE__ */ new Map();
1032
+ const recordBlock = (block, offsetMap) => {
1033
+ byFragmentId.set(block.fragment.fragmentId, block.frame);
1034
+ byBlockId.set(block.fragment.blockId, block.frame);
1035
+ offsetMap.set(block.fragment.from, block.frame);
1036
+ for (const line of block.lines) {
1037
+ for (const anchor of line.anchors) {
1038
+ offsetMap.set(anchor.runtimeOffset, anchor.frame);
1039
+ }
1040
+ }
1041
+ if (block.kind === "table" && block.tablePlan) {
1042
+ recordTableAnchors(
1043
+ block.fragment.blockId,
1044
+ block.frame,
1045
+ block.tablePlan,
1046
+ pxPerTwip,
1047
+ tableCellRects,
1048
+ tableColumnEdges,
1049
+ tableRowEdges
1050
+ );
1051
+ }
1052
+ };
1053
+ const recordStoryRegion = (region) => {
1054
+ const storyKey = storyTargetKey(region.storyTarget);
1055
+ let storyMap = byRuntimeOffsetByStory.get(storyKey);
1056
+ if (!storyMap) {
1057
+ storyMap = /* @__PURE__ */ new Map();
1058
+ byRuntimeOffsetByStory.set(storyKey, storyMap);
1059
+ }
1060
+ for (const block of region.blocks) {
1061
+ recordBlock(block, storyMap);
1062
+ }
1063
+ };
1064
+ for (const page of pages) {
1065
+ byPageIndex.set(page.page.pageIndex, page.frame);
1066
+ for (const block of page.regions.body.blocks) {
1067
+ recordBlock(block, byRuntimeOffset);
1068
+ }
1069
+ if (page.regions.header) recordStoryRegion(page.regions.header);
1070
+ if (page.regions.footer) recordStoryRegion(page.regions.footer);
1071
+ if (page.regions.footnotes) {
1072
+ for (const footnote of page.regions.footnotes) {
1073
+ recordStoryRegion(footnote);
1074
+ }
1075
+ }
1076
+ }
1077
+ const shiftForDeltas = (offset) => {
1078
+ if (pendingDeltas.length === 0) return offset;
1079
+ return offset - sumDeltasBefore(pendingDeltas, offset);
1080
+ };
1081
+ const resolveByRuntimeOffset = (offset, story) => {
1082
+ const lookup = shiftForDeltas(offset);
1083
+ const targetMap = story && story.kind !== "main" ? byRuntimeOffsetByStory.get(storyTargetKey(story)) ?? byRuntimeOffset : byRuntimeOffset;
1084
+ const exact = targetMap.get(lookup);
1085
+ if (exact) return exact;
1086
+ let best = null;
1087
+ let bestDistance = Number.POSITIVE_INFINITY;
1088
+ for (const [key, rect2] of targetMap) {
1089
+ const distance = Math.abs(key - lookup);
1090
+ if (distance < bestDistance) {
1091
+ best = rect2;
1092
+ bestDistance = distance;
1093
+ }
1094
+ }
1095
+ return best;
1096
+ };
1097
+ return {
1098
+ byRuntimeOffset(offset, story) {
1099
+ return resolveByRuntimeOffset(offset, story);
1100
+ },
1101
+ byBlockId(blockId) {
1102
+ return byBlockId.get(blockId) ?? null;
1103
+ },
1104
+ byFragmentId(fragmentId) {
1105
+ return byFragmentId.get(fragmentId) ?? null;
1106
+ },
1107
+ byPageIndex(pageIndex) {
1108
+ return byPageIndex.get(pageIndex) ?? null;
1109
+ },
1110
+ bySelection(fromOffset, toOffset, story) {
1111
+ const lo = Math.min(fromOffset, toOffset);
1112
+ const hi = Math.max(fromOffset, toOffset);
1113
+ if (lo === hi) {
1114
+ return resolveByRuntimeOffset(lo, story);
1115
+ }
1116
+ const loShifted = shiftForDeltas(lo);
1117
+ const hiShifted = shiftForDeltas(hi);
1118
+ const targetMap = story && story.kind !== "main" ? byRuntimeOffsetByStory.get(storyTargetKey(story)) ?? byRuntimeOffset : byRuntimeOffset;
1119
+ let union = null;
1120
+ for (const [key, rect2] of targetMap) {
1121
+ if (key < loShifted || key >= hiShifted) continue;
1122
+ union = unionRects(union, rect2);
1123
+ }
1124
+ if (union) return union;
1125
+ const fromRect = resolveByRuntimeOffset(lo, story);
1126
+ const toRect = resolveByRuntimeOffset(hi - 1, story);
1127
+ return unionRects(fromRect, toRect);
1128
+ },
1129
+ byTableCell(tableBlockId, rowIndex, columnIndex) {
1130
+ return tableCellRects.get(`${tableBlockId}:${rowIndex}:${columnIndex}`) ?? null;
1131
+ },
1132
+ byTableColumnEdge(tableBlockId, columnIndex) {
1133
+ return tableColumnEdges.get(`${tableBlockId}:${columnIndex}`) ?? null;
1134
+ },
1135
+ byTableRowEdge(tableBlockId, rowIndex) {
1136
+ return tableRowEdges.get(`${tableBlockId}:${rowIndex}`) ?? null;
1137
+ },
1138
+ // P9 Phase A — chrome-kind resolvers sourced from the resolved
1139
+ // decoration index. Empty by default (the initial frame build passes
1140
+ // `EMPTY_DECORATION_INDEX` until decoration resolution runs); the
1141
+ // kernel re-invokes `buildAnchorIndex` with the resolved index so the
1142
+ // final anchor index carries chrome-aware lookups.
1143
+ byScopeId(scopeId) {
1144
+ return decorationIndex.workflow.filter((decoration) => decoration.refId === scopeId).map((decoration) => decoration.frame);
1145
+ },
1146
+ byCommentId(commentId) {
1147
+ const match = decorationIndex.comments.find(
1148
+ (decoration) => decoration.refId === commentId
1149
+ );
1150
+ return match?.frame ?? null;
1151
+ },
1152
+ byRevisionId(revisionId) {
1153
+ const match = decorationIndex.revisions.find(
1154
+ (decoration) => decoration.refId === revisionId
1155
+ );
1156
+ return match?.frame ?? null;
1157
+ },
1158
+ // Refactor/05 Slice 7c substrate: object-specific index. Falls back
1159
+ // to `byBlockId` because the render kernel does not yet carry
1160
+ // per-object metadata on anchor frames — the layout facet would
1161
+ // need to emit `byObjectId` entries on the page graph. When that
1162
+ // follow-up ships, populate a dedicated `byObjectIdMap` here and
1163
+ // consult it before the `byBlockId` fallback. The fallback is
1164
+ // correct for block-level drawings (whose object id equals their
1165
+ // block id); it is `heuristic` for inline images (which share
1166
+ // their block id with the enclosing paragraph). `object-handles.ts`
1167
+ // tags those handles `precision: "heuristic"` accordingly.
1168
+ byObjectId(objectId) {
1169
+ return byBlockId.get(objectId) ?? null;
1170
+ }
1171
+ };
1172
+ }
1173
+ function recordTableAnchors(tableBlockId, blockFrame, plan, pxPerTwip, cellRects, columnEdges, rowEdges) {
1174
+ if (!plan) return;
1175
+ const columnCount = plan.columnsTwips.length;
1176
+ if (columnCount === 0) return;
1177
+ const columnLeftsPx = [blockFrame.leftPx];
1178
+ for (let i = 0; i < columnCount; i += 1) {
1179
+ columnLeftsPx.push(
1180
+ columnLeftsPx[i] + (plan.columnsTwips[i] ?? 0) * pxPerTwip
1181
+ );
1182
+ }
1183
+ const rowCount = Math.max(
1184
+ 1,
1185
+ plan.bandClasses.rows.length || plan.bandClasses.cells.reduce(
1186
+ (max, c) => Math.max(max, c.rowIndex + 1),
1187
+ 0
1188
+ )
1189
+ );
1190
+ const rowHeightPx = rowCount > 0 ? blockFrame.heightPx / rowCount : blockFrame.heightPx;
1191
+ const rowTopsPx = [];
1192
+ for (let r = 0; r <= rowCount; r += 1) {
1193
+ rowTopsPx.push(blockFrame.topPx + r * rowHeightPx);
1194
+ }
1195
+ for (const cell of plan.bandClasses.cells) {
1196
+ const sameRow = plan.bandClasses.cells.filter((c) => c.rowIndex === cell.rowIndex);
1197
+ const sorted = [...sameRow].sort((a, b) => a.columnIndex - b.columnIndex);
1198
+ const idx = sorted.findIndex((c) => c === cell);
1199
+ const next = sorted[idx + 1];
1200
+ const columnSpan = (next?.columnIndex ?? columnCount) - cell.columnIndex;
1201
+ const left = columnLeftsPx[cell.columnIndex] ?? blockFrame.leftPx;
1202
+ const right = columnLeftsPx[cell.columnIndex + columnSpan] ?? blockFrame.leftPx + blockFrame.widthPx;
1203
+ const top = rowTopsPx[cell.rowIndex] ?? blockFrame.topPx;
1204
+ const bottom = rowTopsPx[cell.rowIndex + 1] ?? blockFrame.topPx + blockFrame.heightPx;
1205
+ cellRects.set(`${tableBlockId}:${cell.rowIndex}:${cell.columnIndex}`, {
1206
+ leftPx: left,
1207
+ topPx: top,
1208
+ widthPx: Math.max(0, right - left),
1209
+ heightPx: Math.max(0, bottom - top)
1210
+ });
1211
+ }
1212
+ for (const handle of plan.columnResizeHandles) {
1213
+ const x = blockFrame.leftPx + handle.originTwips * pxPerTwip;
1214
+ columnEdges.set(`${tableBlockId}:${handle.columnIndex}`, {
1215
+ leftPx: x,
1216
+ topPx: blockFrame.topPx,
1217
+ widthPx: 0,
1218
+ heightPx: handle.heightTwips * pxPerTwip
1219
+ });
1220
+ }
1221
+ for (let r = 0; r < rowCount - 1; r += 1) {
1222
+ const y = rowTopsPx[r + 1] ?? blockFrame.topPx + blockFrame.heightPx;
1223
+ rowEdges.set(`${tableBlockId}:${r}`, {
1224
+ leftPx: blockFrame.leftPx,
1225
+ topPx: y,
1226
+ widthPx: blockFrame.widthPx,
1227
+ heightPx: 0
1228
+ });
1229
+ }
1230
+ }
1231
+ function unionRects(a, b) {
1232
+ if (!a) return b ?? null;
1233
+ if (!b) return a;
1234
+ const left = Math.min(a.leftPx, b.leftPx);
1235
+ const top = Math.min(a.topPx, b.topPx);
1236
+ const right = Math.max(a.leftPx + a.widthPx, b.leftPx + b.widthPx);
1237
+ const bottom = Math.max(a.topPx + a.heightPx, b.topPx + b.heightPx);
1238
+ return {
1239
+ leftPx: left,
1240
+ topPx: top,
1241
+ widthPx: right - left,
1242
+ heightPx: bottom - top
1243
+ };
1244
+ }
1245
+ function buildDecorationIndex(pages) {
1246
+ const workflow = [];
1247
+ const comments = [];
1248
+ const revisions = [];
1249
+ const search = [];
1250
+ const locked = [];
1251
+ for (const page of pages) {
1252
+ for (const block of page.regions.body.blocks) {
1253
+ for (const decoration of block.blockDecorations) {
1254
+ switch (decoration.kind) {
1255
+ case "workflow":
1256
+ workflow.push(decoration);
1257
+ break;
1258
+ case "comment":
1259
+ comments.push(decoration);
1260
+ break;
1261
+ case "revision":
1262
+ revisions.push(decoration);
1263
+ break;
1264
+ case "search":
1265
+ search.push(decoration);
1266
+ break;
1267
+ case "locked":
1268
+ locked.push(decoration);
1269
+ break;
1270
+ }
1271
+ }
1272
+ }
1273
+ }
1274
+ return { workflow, comments, revisions, search, locked };
1275
+ }
1276
+ function extractRevisionFromPageId(pageId) {
1277
+ const match = /^page-(\d+)-/.exec(pageId);
1278
+ if (!match) return pageId;
1279
+ return Number(match[1]);
1280
+ }
1281
+
113
1282
  // src/core/selection/review-anchors.ts
114
1283
  function detachReviewAnchor(lastKnownRange, reason) {
115
1284
  return createDetachedAnchor(lastKnownRange, reason);
@@ -5112,6 +6281,11 @@ function freezeNumberingLayoutFacts(numbering) {
5112
6281
  if (numbering.numberingSourceRef) Object.freeze(numbering.numberingSourceRef);
5113
6282
  if (numbering.numberingInstanceSourceRef) Object.freeze(numbering.numberingInstanceSourceRef);
5114
6283
  if (numbering.abstractNumberingSourceRef) Object.freeze(numbering.abstractNumberingSourceRef);
6284
+ if (numbering.markerTextPosture) Object.freeze(numbering.markerTextPosture);
6285
+ if (numbering.pictureBulletPosture) {
6286
+ if (numbering.pictureBulletPosture.sourceRef) Object.freeze(numbering.pictureBulletPosture.sourceRef);
6287
+ Object.freeze(numbering.pictureBulletPosture);
6288
+ }
5115
6289
  if (numbering.markerLane) Object.freeze(numbering.markerLane);
5116
6290
  if (numbering.textColumn) Object.freeze(numbering.textColumn);
5117
6291
  if (numbering.tabStops) {
@@ -6087,8 +7261,17 @@ function collectNumberingLayoutFacts(block) {
6087
7261
  ...block.resolvedNumbering?.format !== void 0 ? { format: block.resolvedNumbering.format } : {},
6088
7262
  ...block.resolvedNumbering?.formatPosture !== void 0 ? { formatPosture: { ...block.resolvedNumbering.formatPosture } } : {},
6089
7263
  ...block.numberingPrefix !== void 0 ? { markerText: block.numberingPrefix } : {},
7264
+ ...block.resolvedNumbering?.markerTextPosture !== void 0 ? { markerTextPosture: { ...block.resolvedNumbering.markerTextPosture } } : {},
6090
7265
  ...block.numberingSuffix !== void 0 ? { markerSuffix: block.numberingSuffix } : {},
6091
7266
  ...block.resolvedNumbering?.geometry.markerJustification !== void 0 ? { markerJustification: block.resolvedNumbering.geometry.markerJustification } : {},
7267
+ ...block.resolvedNumbering?.picBulletId !== void 0 ? { picBulletId: block.resolvedNumbering.picBulletId } : {},
7268
+ ...block.resolvedNumbering?.picBulletMediaId !== void 0 ? { picBulletMediaId: block.resolvedNumbering.picBulletMediaId } : {},
7269
+ ...block.resolvedNumbering?.pictureBulletPosture !== void 0 ? {
7270
+ pictureBulletPosture: {
7271
+ ...block.resolvedNumbering.pictureBulletPosture,
7272
+ ...block.resolvedNumbering.pictureBulletPosture.sourceRef !== void 0 ? { sourceRef: { ...block.resolvedNumbering.pictureBulletPosture.sourceRef } } : {}
7273
+ }
7274
+ } : {},
6092
7275
  ...markerLane ? {
6093
7276
  markerLane: {
6094
7277
  startTwips: markerLane.start,
@@ -6903,7 +8086,7 @@ function fnv1a(input) {
6903
8086
 
6904
8087
  // src/runtime/layout/layout-engine-version.ts
6905
8088
  var LAYOUT_ENGINE_VERSION = 93;
6906
- var LAYCACHE_SCHEMA_VERSION = 12;
8089
+ var LAYCACHE_SCHEMA_VERSION = 13;
6907
8090
 
6908
8091
  // src/runtime/layout/layout-engine-instance.ts
6909
8092
  var FULL_VIEWPORT_WINDOW_KEY = "full";
@@ -7941,33 +9124,6 @@ function resolveProjectedRuntimeRange(offsetMap, from, to) {
7941
9124
  return { from: runtimeFrom, to: runtimeTo };
7942
9125
  }
7943
9126
 
7944
- // src/runtime/render/render-frame-types.ts
7945
- var DEFAULT_PX_PER_TWIP = 96 / 1440;
7946
- var PAGE_STACK_GAP_PX = 48;
7947
- function resolveDefaultZoom(input = {}) {
7948
- return {
7949
- pxPerTwip: input.pxPerTwip ?? DEFAULT_PX_PER_TWIP,
7950
- viewportWidthPx: input.viewportWidthPx ?? 900,
7951
- fitMode: input.fitMode ?? "fixed"
7952
- };
7953
- }
7954
- var EMPTY_DECORATION_INDEX = Object.freeze({
7955
- workflow: Object.freeze([]),
7956
- comments: Object.freeze([]),
7957
- revisions: Object.freeze([]),
7958
- search: Object.freeze([]),
7959
- locked: Object.freeze([])
7960
- });
7961
- function defaultChromeReservations(layout, zoom) {
7962
- return {
7963
- railLaneTwips: 360,
7964
- balloonLaneTwips: 2160,
7965
- footnoteAreaTwips: 0,
7966
- pageFrameWidthPx: layout.pageWidth * zoom.pxPerTwip,
7967
- pageFrameHeightPx: layout.pageHeight * zoom.pxPerTwip
7968
- };
7969
- }
7970
-
7971
9127
  // src/runtime/markdown-sanitizer.ts
7972
9128
  function sanitizeMarkdown(raw) {
7973
9129
  let sanitized = false;
@@ -8080,6 +9236,16 @@ export {
8080
9236
  DEFAULT_UNKNOWN_BEHAVIOR,
8081
9237
  DEFAULT_REGISTRY_ENTRIES,
8082
9238
  createScopeTagRegistry,
9239
+ PREDICTED_LANE_COUNTERS,
9240
+ startPerfProbe,
9241
+ finishPerfProbe,
9242
+ recordPerfSample,
9243
+ incrementInvalidationCounter,
9244
+ createPagePatchPlan,
9245
+ DEFAULT_PX_PER_TWIP,
9246
+ PAGE_STACK_GAP_PX,
9247
+ resolveDefaultZoom,
9248
+ createRenderKernel,
8083
9249
  detachReviewAnchor,
8084
9250
  mapReviewAnchor,
8085
9251
  getAnchorRange,
@@ -8127,11 +9293,6 @@ export {
8127
9293
  searchProjectedSurfaceText,
8128
9294
  searchSecondaryStories,
8129
9295
  projectSurfaceText,
8130
- DEFAULT_PX_PER_TWIP,
8131
- PAGE_STACK_GAP_PX,
8132
- resolveDefaultZoom,
8133
- EMPTY_DECORATION_INDEX,
8134
- defaultChromeReservations,
8135
9296
  sanitizeMarkdown,
8136
9297
  sha256Hex,
8137
9298
  ISSUE_METADATA_ID,