@beyondwork/docx-react-component 1.0.127 → 1.0.129

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 +215 -61
  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 +2 -2
  5. package/dist/api/v3.cjs +1324 -71
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +8 -8
  9. package/dist/{canonical-document-CXCFCbAz.d.cts → canonical-document-BMtONpgf.d.cts} +6 -0
  10. package/dist/{canonical-document-CXCFCbAz.d.ts → canonical-document-BMtONpgf.d.ts} +6 -0
  11. package/dist/{chunk-KV435YXO.js → chunk-5DSHUYSY.js} +1 -1
  12. package/dist/{chunk-TQDQU2E3.js → chunk-63FYIGCT.js} +2 -2
  13. package/dist/{chunk-ZDOAUP3V.js → chunk-DDN2AIGE.js} +1 -1
  14. package/dist/{chunk-6F5QW44A.js → chunk-DJU2W4E4.js} +2 -2
  15. package/dist/{chunk-4EENH4FG.js → chunk-EZKJXIPH.js} +1 -1
  16. package/dist/{chunk-CXSYRB37.js → chunk-HUIHBBAQ.js} +166 -49
  17. package/dist/{chunk-ESJ2MES5.js → chunk-JJGVE5J7.js} +1 -1
  18. package/dist/{chunk-LZVBNDGU.js → chunk-LJH64PV3.js} +3 -3
  19. package/dist/{chunk-MWSBGJQO.js → chunk-OTQIW2TC.js} +2 -2
  20. package/dist/{chunk-2QL5DAKF.js → chunk-PGKUJZXV.js} +3 -3
  21. package/dist/{chunk-PUMZWE2D.js → chunk-PRAZBHNF.js} +460 -136
  22. package/dist/{chunk-4YJVRIUB.js → chunk-Q3QYGKFE.js} +51 -8
  23. package/dist/{chunk-YHZHPXDB.js → chunk-RMRTQGW3.js} +50 -13
  24. package/dist/{chunk-XRACP43Q.js → chunk-SKPTKQHF.js} +351 -13
  25. package/dist/{chunk-D5HYZQTG.js → chunk-VNLDQJ47.js} +1 -1
  26. package/dist/{chunk-BYSRJ4FE.js → chunk-W34X3KBR.js} +1 -1
  27. package/dist/{chunk-V6XVZFFH.js → chunk-XMHSGPLN.js} +2 -2
  28. package/dist/{chunk-46KNRA4C.js → chunk-XQCAMKIQ.js} +849 -6
  29. package/dist/{chunk-YD2JE54B.js → chunk-YZDZ4FGR.js} +1 -1
  30. package/dist/compare.d.cts +1 -1
  31. package/dist/compare.d.ts +1 -1
  32. package/dist/core/commands/formatting-commands.d.cts +2 -2
  33. package/dist/core/commands/formatting-commands.d.ts +2 -2
  34. package/dist/core/commands/image-commands.cjs +166 -49
  35. package/dist/core/commands/image-commands.d.cts +2 -2
  36. package/dist/core/commands/image-commands.d.ts +2 -2
  37. package/dist/core/commands/image-commands.js +4 -4
  38. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  39. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  40. package/dist/core/commands/style-commands.d.cts +2 -2
  41. package/dist/core/commands/style-commands.d.ts +2 -2
  42. package/dist/core/commands/table-structure-commands.cjs +166 -49
  43. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  44. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  45. package/dist/core/commands/table-structure-commands.js +3 -3
  46. package/dist/core/commands/text-commands.cjs +166 -49
  47. package/dist/core/commands/text-commands.d.cts +2 -2
  48. package/dist/core/commands/text-commands.d.ts +2 -2
  49. package/dist/core/commands/text-commands.js +4 -4
  50. package/dist/core/selection/mapping.d.cts +2 -2
  51. package/dist/core/selection/mapping.d.ts +2 -2
  52. package/dist/core/state/editor-state.d.cts +2 -2
  53. package/dist/core/state/editor-state.d.ts +2 -2
  54. package/dist/index.cjs +1943 -219
  55. package/dist/index.d.cts +5 -5
  56. package/dist/index.d.ts +5 -5
  57. package/dist/index.js +56 -22
  58. package/dist/io/docx-session.cjs +51 -8
  59. package/dist/io/docx-session.d.cts +4 -4
  60. package/dist/io/docx-session.d.ts +4 -4
  61. package/dist/io/docx-session.js +3 -3
  62. package/dist/legal.d.cts +1 -1
  63. package/dist/legal.d.ts +1 -1
  64. package/dist/legal.js +2 -2
  65. package/dist/{loader-CFICtb9m.d.ts → loader-4qsw4eIU.d.ts} +3 -3
  66. package/dist/{loader-DveZOVuC.d.cts → loader-B8TKhmQi.d.cts} +3 -3
  67. package/dist/{public-types-beSYFJRR.d.cts → public-types-B5CRoR6f.d.cts} +220 -1
  68. package/dist/{public-types-Cgl3efbO.d.ts → public-types-p9b8rfy8.d.ts} +220 -1
  69. package/dist/public-types.cjs +215 -61
  70. package/dist/public-types.d.cts +2 -2
  71. package/dist/public-types.d.ts +2 -2
  72. package/dist/public-types.js +2 -2
  73. package/dist/runtime/collab.d.cts +3 -3
  74. package/dist/runtime/collab.d.ts +3 -3
  75. package/dist/runtime/document-runtime.cjs +999 -193
  76. package/dist/runtime/document-runtime.d.cts +2 -2
  77. package/dist/runtime/document-runtime.d.ts +2 -2
  78. package/dist/runtime/document-runtime.js +13 -13
  79. package/dist/{session-B7u82EJF.d.cts → session-BnGIjaex.d.cts} +3 -3
  80. package/dist/{session-BWMJ9jm4.d.ts → session-vEYKf-w3.d.ts} +3 -3
  81. package/dist/session.cjs +51 -8
  82. package/dist/session.d.cts +5 -5
  83. package/dist/session.d.ts +5 -5
  84. package/dist/session.js +4 -4
  85. package/dist/tailwind.cjs +215 -61
  86. package/dist/tailwind.d.cts +2 -2
  87. package/dist/tailwind.d.ts +2 -2
  88. package/dist/tailwind.js +5 -5
  89. package/dist/{types-BQjdVZsh.d.cts → types-BLuvZ6cQ.d.cts} +2 -2
  90. package/dist/{types-DvvmS5A7.d.ts → types-Dutlyj0T.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 +3 -3
  94. package/dist/ui-tailwind.cjs +215 -61
  95. package/dist/ui-tailwind.d.cts +3 -3
  96. package/dist/ui-tailwind.d.ts +3 -3
  97. package/dist/ui-tailwind.js +5 -5
  98. package/package.json +1 -1
@@ -9317,12 +9317,13 @@ function getLevelStartAt(level, levelDefinitions) {
9317
9317
  return levelDefinitions.get(level)?.startAt ?? DEFAULT_NUMBERING_START_AT;
9318
9318
  }
9319
9319
  function getNumberingFormatPosture(format, value) {
9320
- if (!isSupportedNumberingFormat(format)) {
9320
+ const registryEntry = getNumberingFormatRegistryEntry(format);
9321
+ if (!registryEntry || registryEntry.renderSupport === "approximated") {
9321
9322
  return {
9322
9323
  status: "approximated",
9323
9324
  requestedFormat: format,
9324
9325
  renderedFormat: "decimal",
9325
- reason: "unsupported-numbering-format-decimal-fallback"
9326
+ reason: registryEntry?.fallbackReason ?? "unsupported-numbering-format-decimal-fallback"
9326
9327
  };
9327
9328
  }
9328
9329
  if (value !== void 0 && ((format === "upperRoman" || format === "lowerRoman") && (value <= 0 || value >= 4e3) || (format === "cardinalText" || format === "ordinalText") && (!Number.isInteger(value) || value < 1 || value > 999) || (format === "upperLetter" || format === "lowerLetter" || format === "chicago") && value < 1)) {
@@ -9353,56 +9354,148 @@ function renderLevelText(text, counters, levelDefinitions) {
9353
9354
  });
9354
9355
  return rendered.trim().length > 0 ? rendered : null;
9355
9356
  }
9356
- var SUPPORTED_NUMBERING_FORMATS = /* @__PURE__ */ new Set([
9357
- "decimal",
9358
- "decimalZero",
9359
- "upperLetter",
9360
- "lowerLetter",
9361
- "upperRoman",
9362
- "lowerRoman",
9363
- "hex",
9364
- "ordinal",
9365
- "cardinalText",
9366
- "ordinalText",
9367
- "chicago",
9368
- "bullet",
9369
- "none"
9370
- ]);
9371
9357
  function isSupportedNumberingFormat(format) {
9372
- return SUPPORTED_NUMBERING_FORMATS.has(format);
9358
+ return getNumberingFormatRegistryEntry(format)?.renderSupport === "supported";
9359
+ }
9360
+ function getNumberingFormatRegistryEntry(format) {
9361
+ return NUMBERING_FORMAT_REGISTRY.get(format);
9373
9362
  }
9374
9363
  function formatCounter(value, format) {
9375
- switch (format) {
9376
- case "decimal":
9377
- return String(value);
9378
- case "decimalZero":
9379
- return String(value).padStart(2, "0");
9380
- case "upperLetter":
9381
- return toAlphabetic2(value).toUpperCase();
9382
- case "lowerLetter":
9383
- return toAlphabetic2(value).toLowerCase();
9384
- case "upperRoman":
9385
- return toRoman2(value).toUpperCase();
9386
- case "lowerRoman":
9387
- return toRoman2(value).toLowerCase();
9388
- case "hex":
9389
- return value >= 0 ? value.toString(16).toUpperCase() : String(value);
9390
- case "ordinal":
9391
- return toOrdinal2(value);
9392
- case "cardinalText":
9393
- return toCardinalText2(value);
9394
- case "ordinalText":
9395
- return toOrdinalText2(value);
9396
- case "chicago":
9397
- return toChicago2(value);
9398
- case "bullet":
9399
- return "";
9400
- case "none":
9401
- return "";
9402
- default:
9403
- return String(value);
9404
- }
9364
+ return getNumberingFormatRegistryEntry(format)?.render(value) ?? String(value);
9405
9365
  }
9366
+ var exactNumberingFormatEntries = [
9367
+ {
9368
+ format: "decimal",
9369
+ renderSupport: "supported",
9370
+ renderedFormat: "decimal",
9371
+ supportsMutation: true,
9372
+ render: (value) => String(value)
9373
+ },
9374
+ {
9375
+ format: "decimalZero",
9376
+ renderSupport: "supported",
9377
+ renderedFormat: "decimalZero",
9378
+ supportsMutation: true,
9379
+ render: (value) => String(value).padStart(2, "0")
9380
+ },
9381
+ {
9382
+ format: "upperLetter",
9383
+ renderSupport: "supported",
9384
+ renderedFormat: "upperLetter",
9385
+ supportsMutation: true,
9386
+ render: (value) => toAlphabetic2(value).toUpperCase()
9387
+ },
9388
+ {
9389
+ format: "lowerLetter",
9390
+ renderSupport: "supported",
9391
+ renderedFormat: "lowerLetter",
9392
+ supportsMutation: true,
9393
+ render: (value) => toAlphabetic2(value).toLowerCase()
9394
+ },
9395
+ {
9396
+ format: "upperRoman",
9397
+ renderSupport: "supported",
9398
+ renderedFormat: "upperRoman",
9399
+ supportsMutation: true,
9400
+ render: (value) => toRoman2(value).toUpperCase()
9401
+ },
9402
+ {
9403
+ format: "lowerRoman",
9404
+ renderSupport: "supported",
9405
+ renderedFormat: "lowerRoman",
9406
+ supportsMutation: true,
9407
+ render: (value) => toRoman2(value).toLowerCase()
9408
+ },
9409
+ {
9410
+ format: "hex",
9411
+ renderSupport: "supported",
9412
+ renderedFormat: "hex",
9413
+ supportsMutation: true,
9414
+ render: (value) => value >= 0 ? value.toString(16).toUpperCase() : String(value)
9415
+ },
9416
+ {
9417
+ format: "ordinal",
9418
+ renderSupport: "supported",
9419
+ renderedFormat: "ordinal",
9420
+ supportsMutation: true,
9421
+ render: toOrdinal2
9422
+ },
9423
+ {
9424
+ format: "cardinalText",
9425
+ renderSupport: "supported",
9426
+ renderedFormat: "cardinalText",
9427
+ supportsMutation: true,
9428
+ render: toCardinalText2
9429
+ },
9430
+ {
9431
+ format: "ordinalText",
9432
+ renderSupport: "supported",
9433
+ renderedFormat: "ordinalText",
9434
+ supportsMutation: true,
9435
+ render: toOrdinalText2
9436
+ },
9437
+ {
9438
+ format: "chicago",
9439
+ renderSupport: "supported",
9440
+ renderedFormat: "chicago",
9441
+ supportsMutation: true,
9442
+ render: toChicago2
9443
+ },
9444
+ {
9445
+ format: "bullet",
9446
+ renderSupport: "supported",
9447
+ renderedFormat: "bullet",
9448
+ supportsMutation: true,
9449
+ render: () => ""
9450
+ },
9451
+ {
9452
+ format: "none",
9453
+ renderSupport: "supported",
9454
+ renderedFormat: "none",
9455
+ supportsMutation: true,
9456
+ render: () => ""
9457
+ }
9458
+ ];
9459
+ var approximatedDecimalFormats = [
9460
+ "decimalEnclosedCircle",
9461
+ "decimalEnclosedFullstop",
9462
+ "decimalEnclosedParen",
9463
+ "decimalFullWidth",
9464
+ "decimalHalfWidth",
9465
+ "aiueo",
9466
+ "iroha",
9467
+ "ganada",
9468
+ "chosung",
9469
+ "russianLower",
9470
+ "russianUpper",
9471
+ "hebrew1",
9472
+ "hebrew2",
9473
+ "arabicAlpha",
9474
+ "arabicAbjad",
9475
+ "thaiLetters",
9476
+ "thaiNumbers",
9477
+ "hindiLetters",
9478
+ "hindiNumbers",
9479
+ "ideographDigital",
9480
+ "ideographTraditional",
9481
+ "chineseCounting",
9482
+ "japaneseCounting",
9483
+ "japaneseLegal"
9484
+ ];
9485
+ var approximatedNumberingFormatEntries = approximatedDecimalFormats.map((format) => ({
9486
+ format,
9487
+ renderSupport: "approximated",
9488
+ renderedFormat: "decimal",
9489
+ supportsMutation: false,
9490
+ fallbackReason: "unsupported-numbering-format-decimal-fallback",
9491
+ render: (value) => String(value)
9492
+ }));
9493
+ var NUMBERING_FORMAT_REGISTRY = new Map(
9494
+ [...exactNumberingFormatEntries, ...approximatedNumberingFormatEntries].map((entry) => [
9495
+ entry.format,
9496
+ entry
9497
+ ])
9498
+ );
9406
9499
  function toOrdinal2(value) {
9407
9500
  if (value <= 0) return String(value);
9408
9501
  const lastTwo = value % 100;
@@ -10056,12 +10149,36 @@ var DEFAULT_HYPERLINK_COLOR_HEX = "0563C1";
10056
10149
  function resolveHyperlinkRunFormatting(input, catalog, resolver) {
10057
10150
  const augmentedInput = input.characterStyleId === void 0 ? { ...input, characterStyleId: HYPERLINK_CHARACTER_STYLE_ID } : input;
10058
10151
  const cascade = resolveEffectiveRunFormatting(augmentedInput, catalog);
10059
- const resolvedColor = resolveHyperlinkColorHex(cascade, resolver);
10152
+ const resolvedColor = resolveHyperlinkColorHex(
10153
+ stripInheritedColorHexForImplicitHyperlink(input, catalog, cascade),
10154
+ resolver
10155
+ );
10060
10156
  if (resolvedColor && resolvedColor !== cascade.colorHex) {
10061
10157
  return { ...cascade, colorHex: resolvedColor };
10062
10158
  }
10063
10159
  return cascade;
10064
10160
  }
10161
+ function hasDirectNonAutoColor(input) {
10162
+ return Boolean(input.direct?.colorHex && input.direct.colorHex !== "auto");
10163
+ }
10164
+ function characterStyleDeclaresColorHex(styleId, catalog) {
10165
+ if (!catalog) return false;
10166
+ const chain = resolveCharacterStyleChain(styleId, catalog);
10167
+ return chain.some((chainStyleId) => {
10168
+ const colorHex = catalog.characters[chainStyleId]?.runProperties?.colorHex;
10169
+ return Boolean(colorHex && colorHex !== "auto");
10170
+ });
10171
+ }
10172
+ function stripInheritedColorHexForImplicitHyperlink(originalInput, catalog, cascade) {
10173
+ if (originalInput.characterStyleId !== void 0 || hasDirectNonAutoColor(originalInput) || !cascade.colorHex || cascade.colorHex === "auto" || characterStyleDeclaresColorHex(HYPERLINK_CHARACTER_STYLE_ID, catalog)) {
10174
+ return cascade;
10175
+ }
10176
+ const inheritedCascade = resolveEffectiveRunFormatting(originalInput, catalog);
10177
+ if (inheritedCascade.colorHex !== cascade.colorHex) {
10178
+ return cascade;
10179
+ }
10180
+ return { ...cascade, colorHex: void 0 };
10181
+ }
10065
10182
  function resolveHyperlinkColorHex(cascade, resolver) {
10066
10183
  if (cascade.colorHex && cascade.colorHex !== "auto") {
10067
10184
  return cascade.colorHex;
@@ -18920,6 +19037,133 @@ function rangesOverlap2(leftFrom, leftTo, rightFrom, rightTo) {
18920
19037
  return leftFrom < rightTo && leftTo > rightFrom;
18921
19038
  }
18922
19039
 
19040
+ // src/io/ooxml/numbering-catalog-mutation.ts
19041
+ function cloneNumberingCatalog(catalog) {
19042
+ return structuredClone(catalog);
19043
+ }
19044
+ function getListKind(catalog, numberingInstanceId) {
19045
+ const instance = catalog.instances[numberingInstanceId];
19046
+ const definition = instance ? catalog.abstractDefinitions[instance.abstractNumberingId] : void 0;
19047
+ const levelZero = definition?.levels.find((level) => level.level === 0);
19048
+ if (!levelZero) return void 0;
19049
+ return levelZero.format === "bullet" ? "bulleted" : "numbered";
19050
+ }
19051
+ function ensureDefaultListInstance(catalog, kind) {
19052
+ const existing = Object.values(catalog.instances).find(
19053
+ (instance) => getListKind(catalog, instance.numberingInstanceId) === kind
19054
+ );
19055
+ if (existing) return existing.numberingInstanceId;
19056
+ const abstractNumberingId = allocateAbstractDefinition(catalog, {
19057
+ levels: defaultLevels(kind),
19058
+ multiLevelType: "hybridMultilevel"
19059
+ });
19060
+ return allocateNumberingInstance(catalog, abstractNumberingId);
19061
+ }
19062
+ function allocateNumberingInstance(catalog, abstractNumberingId, overrides = []) {
19063
+ const numberingInstanceId = nextCanonicalNumericId(
19064
+ "num:",
19065
+ Object.keys(catalog.instances)
19066
+ );
19067
+ catalog.instances[numberingInstanceId] = {
19068
+ numberingInstanceId,
19069
+ abstractNumberingId,
19070
+ overrides: cloneOverrides(overrides)
19071
+ };
19072
+ return numberingInstanceId;
19073
+ }
19074
+ function allocateAbstractDefinition(catalog, input) {
19075
+ const abstractNumberingId = input.abstractNumberingId && !catalog.abstractDefinitions[input.abstractNumberingId] ? input.abstractNumberingId : nextCanonicalNumericId("abstract-num:", Object.keys(catalog.abstractDefinitions));
19076
+ catalog.abstractDefinitions[abstractNumberingId] = {
19077
+ abstractNumberingId,
19078
+ levels: structuredClone(input.levels),
19079
+ ...input.nsid ? { nsid: input.nsid } : { nsid: freshLongHex(catalog, abstractNumberingId, "nsid") },
19080
+ ...input.multiLevelType ? { multiLevelType: input.multiLevelType } : {},
19081
+ ...input.tplc ? { tplc: input.tplc } : { tplc: freshLongHex(catalog, abstractNumberingId, "tmpl") },
19082
+ ...input.styleLink ? { styleLink: input.styleLink } : {},
19083
+ ...input.numStyleLink ? { numStyleLink: input.numStyleLink } : {}
19084
+ };
19085
+ return abstractNumberingId;
19086
+ }
19087
+ function setStartOverride(catalog, numberingInstanceId, level, startAt) {
19088
+ const instance = catalog.instances[numberingInstanceId];
19089
+ if (!instance) return;
19090
+ catalog.instances[numberingInstanceId] = {
19091
+ ...instance,
19092
+ overrides: mergeOverride(instance.overrides, { level, startAt })
19093
+ };
19094
+ }
19095
+ function mergeOverride(overrides, nextOverride) {
19096
+ return [
19097
+ ...overrides.filter((override) => override.level !== nextOverride.level),
19098
+ structuredClone(nextOverride)
19099
+ ].sort((left, right) => left.level - right.level);
19100
+ }
19101
+ function cloneOverrides(overrides) {
19102
+ return overrides.map((override) => structuredClone(override));
19103
+ }
19104
+ function defaultLevels(kind) {
19105
+ if (kind === "bulleted") {
19106
+ return [
19107
+ { level: 0, format: "bullet", text: "\u2022" },
19108
+ { level: 1, format: "bullet", text: "o" },
19109
+ { level: 2, format: "bullet", text: "\u25A0" },
19110
+ { level: 3, format: "bullet", text: "\u2022" },
19111
+ { level: 4, format: "bullet", text: "o" },
19112
+ { level: 5, format: "bullet", text: "\u25A0" },
19113
+ { level: 6, format: "bullet", text: "\u2022" },
19114
+ { level: 7, format: "bullet", text: "o" },
19115
+ { level: 8, format: "bullet", text: "\u25A0" }
19116
+ ];
19117
+ }
19118
+ return [
19119
+ { level: 0, format: "decimal", text: "%1." },
19120
+ { level: 1, format: "decimal", text: "%1.%2." },
19121
+ { level: 2, format: "lowerLetter", text: "(%3)" },
19122
+ { level: 3, format: "lowerRoman", text: "(%4)" },
19123
+ { level: 4, format: "decimal", text: "%5." },
19124
+ { level: 5, format: "lowerLetter", text: "(%6)" },
19125
+ { level: 6, format: "lowerRoman", text: "(%7)" },
19126
+ { level: 7, format: "decimal", text: "%8." },
19127
+ { level: 8, format: "lowerLetter", text: "(%9)" }
19128
+ ];
19129
+ }
19130
+ function nextCanonicalNumericId(prefix, ids) {
19131
+ return `${prefix}${nextNumericString(ids.map((id) => stripPrefix(id, prefix)))}`;
19132
+ }
19133
+ function nextNumericString(ids) {
19134
+ const used = new Set(ids);
19135
+ let next = 1;
19136
+ for (const id of ids) {
19137
+ const parsed = Number.parseInt(id, 10);
19138
+ if (Number.isFinite(parsed) && parsed >= next) next = parsed + 1;
19139
+ }
19140
+ while (used.has(String(next))) next += 1;
19141
+ return String(next);
19142
+ }
19143
+ function stripPrefix(value, prefix) {
19144
+ return value.startsWith(prefix) ? value.slice(prefix.length) : value;
19145
+ }
19146
+ function freshLongHex(catalog, abstractNumberingId, salt) {
19147
+ const existing = new Set(
19148
+ Object.values(catalog.abstractDefinitions).map((definition) => salt === "nsid" ? definition.nsid : definition.tplc).filter((value) => Boolean(value))
19149
+ );
19150
+ let attempt = 0;
19151
+ while (attempt < 1e3) {
19152
+ const candidate = hashLongHex(`${salt}:${abstractNumberingId}:${attempt}`);
19153
+ if (!existing.has(candidate)) return candidate;
19154
+ attempt += 1;
19155
+ }
19156
+ return hashLongHex(`${salt}:${abstractNumberingId}:${Date.now()}`);
19157
+ }
19158
+ function hashLongHex(input) {
19159
+ let hash = 2166136261;
19160
+ for (let index = 0; index < input.length; index += 1) {
19161
+ hash ^= input.charCodeAt(index);
19162
+ hash = Math.imul(hash, 16777619) >>> 0;
19163
+ }
19164
+ return hash.toString(16).toUpperCase().padStart(8, "0").slice(-8);
19165
+ }
19166
+
18923
19167
  // src/core/commands/list-commands.ts
18924
19168
  function toggleNumberedList(document2, paragraphIndexes, context, options = {}) {
18925
19169
  return toggleListKind(document2, paragraphIndexes, "numbered", context, options);
@@ -18964,7 +19208,7 @@ function restartNumbering(document2, paragraphIndex, context, startAt = 1, optio
18964
19208
  affectedParagraphIndexes: []
18965
19209
  };
18966
19210
  }
18967
- const catalog = ensureNumberingCatalog(working.numbering);
19211
+ const catalog = cloneNumberingCatalog(working.numbering);
18968
19212
  const existingInstance = catalog.instances[target.numbering.numberingInstanceId];
18969
19213
  if (!existingInstance) {
18970
19214
  return {
@@ -18972,15 +19216,12 @@ function restartNumbering(document2, paragraphIndex, context, startAt = 1, optio
18972
19216
  affectedParagraphIndexes: []
18973
19217
  };
18974
19218
  }
18975
- const numberingInstanceId = createNumberingInstanceId(catalog);
18976
- catalog.instances[numberingInstanceId] = {
18977
- numberingInstanceId,
18978
- abstractNumberingId: existingInstance.abstractNumberingId,
18979
- overrides: mergeOverride(existingInstance.overrides, {
18980
- level: target.numbering.level,
18981
- startAt
18982
- })
18983
- };
19219
+ const numberingInstanceId = allocateNumberingInstance(
19220
+ catalog,
19221
+ existingInstance.abstractNumberingId,
19222
+ existingInstance.overrides
19223
+ );
19224
+ setStartOverride(catalog, numberingInstanceId, target.numbering.level, startAt);
18984
19225
  const affectedParagraphIndexes = [];
18985
19226
  for (let index = resolvedParagraphIndex; index < paragraphs.length; index += 1) {
18986
19227
  const paragraph = paragraphs[index];
@@ -19034,7 +19275,7 @@ function continueNumbering(document2, paragraphIndex, context, options = {}) {
19034
19275
  affectedParagraphIndexes: []
19035
19276
  };
19036
19277
  }
19037
- const catalog = ensureNumberingCatalog(working.numbering);
19278
+ const catalog = cloneNumberingCatalog(working.numbering);
19038
19279
  const currentInstanceId = target.numbering.numberingInstanceId;
19039
19280
  const currentKind = getListKind(catalog, currentInstanceId);
19040
19281
  if (!currentKind) {
@@ -19101,7 +19342,7 @@ function toggleListKind(document2, paragraphIndexes, kind, context, options) {
19101
19342
  affectedParagraphIndexes: []
19102
19343
  };
19103
19344
  }
19104
- const catalog = ensureNumberingCatalog(working.numbering);
19345
+ const catalog = cloneNumberingCatalog(working.numbering);
19105
19346
  const allAlreadyKind = normalizedIndexes.every((index) => {
19106
19347
  const paragraph = paragraphs[index];
19107
19348
  return paragraph.numbering ? getListKind(catalog, paragraph.numbering.numberingInstanceId) === kind : false;
@@ -19116,7 +19357,7 @@ function toggleListKind(document2, paragraphIndexes, kind, context, options) {
19116
19357
  affectedParagraphIndexes: normalizedIndexes
19117
19358
  };
19118
19359
  }
19119
- const numberingInstanceId = findAdjacentCompatibleInstance(paragraphs, catalog, normalizedIndexes[0], kind) ?? ensureDefaultInstance(catalog, kind);
19360
+ const numberingInstanceId = findAdjacentCompatibleInstance(paragraphs, catalog, normalizedIndexes[0], kind) ?? ensureDefaultListInstance(catalog, kind);
19120
19361
  for (const index of normalizedIndexes) {
19121
19362
  const paragraph = paragraphs[index];
19122
19363
  paragraph.numbering = {
@@ -19281,23 +19522,6 @@ function sortJson(value) {
19281
19522
  }
19282
19523
  return value;
19283
19524
  }
19284
- function ensureDefaultInstance(catalog, kind) {
19285
- const existing = Object.values(catalog.instances).find(
19286
- (instance) => getListKind(catalog, instance.numberingInstanceId) === kind
19287
- );
19288
- if (existing) {
19289
- return existing.numberingInstanceId;
19290
- }
19291
- const abstractNumberingId = createAbstractNumberingId(catalog);
19292
- catalog.abstractDefinitions[abstractNumberingId] = kind === "bulleted" ? createDefaultBulletedDefinition(abstractNumberingId) : createDefaultNumberedDefinition(abstractNumberingId);
19293
- const numberingInstanceId = createNumberingInstanceId(catalog);
19294
- catalog.instances[numberingInstanceId] = {
19295
- numberingInstanceId,
19296
- abstractNumberingId,
19297
- overrides: []
19298
- };
19299
- return numberingInstanceId;
19300
- }
19301
19525
  function findAdjacentCompatibleInstance(paragraphs, catalog, fromIndex, kind) {
19302
19526
  const previous = paragraphs[fromIndex - 1];
19303
19527
  if (previous?.numbering) {
@@ -19320,69 +19544,6 @@ function findPreviousCompatibleInstance(paragraphs, catalog, fromIndex, kind) {
19320
19544
  }
19321
19545
  return void 0;
19322
19546
  }
19323
- function getListKind(catalog, numberingInstanceId) {
19324
- const instance = catalog.instances[numberingInstanceId];
19325
- const definition = instance ? catalog.abstractDefinitions[instance.abstractNumberingId] : void 0;
19326
- const levelZero = definition?.levels.find((level) => level.level === 0);
19327
- if (!levelZero) {
19328
- return void 0;
19329
- }
19330
- return levelZero.format === "bullet" ? "bulleted" : "numbered";
19331
- }
19332
- function mergeOverride(overrides, nextOverride) {
19333
- const filtered = overrides.filter((override) => override.level !== nextOverride.level);
19334
- filtered.push(nextOverride);
19335
- return filtered.sort((left, right) => left.level - right.level);
19336
- }
19337
- function createDefaultNumberedDefinition(abstractNumberingId) {
19338
- return {
19339
- abstractNumberingId,
19340
- levels: [
19341
- { level: 0, format: "decimal", text: "%1." },
19342
- { level: 1, format: "decimal", text: "%1.%2." },
19343
- { level: 2, format: "lowerLetter", text: "(%3)" },
19344
- { level: 3, format: "lowerRoman", text: "(%4)" },
19345
- { level: 4, format: "decimal", text: "%5." },
19346
- { level: 5, format: "lowerLetter", text: "(%6)" },
19347
- { level: 6, format: "lowerRoman", text: "(%7)" },
19348
- { level: 7, format: "decimal", text: "%8." },
19349
- { level: 8, format: "lowerLetter", text: "(%9)" }
19350
- ]
19351
- };
19352
- }
19353
- function createDefaultBulletedDefinition(abstractNumberingId) {
19354
- return {
19355
- abstractNumberingId,
19356
- levels: [
19357
- { level: 0, format: "bullet", text: "\u2022" },
19358
- { level: 1, format: "bullet", text: "o" },
19359
- { level: 2, format: "bullet", text: "\u25A0" },
19360
- { level: 3, format: "bullet", text: "\u2022" },
19361
- { level: 4, format: "bullet", text: "o" },
19362
- { level: 5, format: "bullet", text: "\u25A0" },
19363
- { level: 6, format: "bullet", text: "\u2022" },
19364
- { level: 7, format: "bullet", text: "o" },
19365
- { level: 8, format: "bullet", text: "\u25A0" }
19366
- ]
19367
- };
19368
- }
19369
- function createAbstractNumberingId(catalog) {
19370
- let index = 1;
19371
- while (catalog.abstractDefinitions[`abstract-num:generated-${index}`]) {
19372
- index += 1;
19373
- }
19374
- return `abstract-num:generated-${index}`;
19375
- }
19376
- function createNumberingInstanceId(catalog) {
19377
- let index = 1;
19378
- while (catalog.instances[`num:generated-${index}`]) {
19379
- index += 1;
19380
- }
19381
- return `num:generated-${index}`;
19382
- }
19383
- function ensureNumberingCatalog(value) {
19384
- return structuredClone(value);
19385
- }
19386
19547
  function cloneEnvelope(document2, timestamp) {
19387
19548
  return {
19388
19549
  ...structuredClone(document2),
@@ -20108,7 +20269,7 @@ function applyFragmentInsert(document2, selection, fragment, context) {
20108
20269
  );
20109
20270
  workingDocument = collapseResult.document;
20110
20271
  workingSelection = collapseResult.selection;
20111
- if (context.textTarget?.kind === "table-paragraph") {
20272
+ if (context.textTarget?.kind === "table-paragraph" || context.textTarget?.kind === "text-leaf") {
20112
20273
  workingContext = {
20113
20274
  ...context,
20114
20275
  textTarget: {
@@ -20130,11 +20291,11 @@ function applyFragmentInsert(document2, selection, fragment, context) {
20130
20291
  selection
20131
20292
  };
20132
20293
  }
20133
- const targetedTablePath = workingContext.textTarget?.kind === "table-paragraph" ? workingContext.textTarget.blockPath : void 0;
20134
- if (targetedTablePath) {
20294
+ const targetedBlockPath = workingContext.textTarget?.kind === "table-paragraph" || workingContext.textTarget?.kind === "text-leaf" ? workingContext.textTarget.blockPath : void 0;
20295
+ if (targetedBlockPath) {
20135
20296
  const targeted = insertFragmentBlocksAfterPath(
20136
20297
  splitResult.document,
20137
- targetedTablePath,
20298
+ targetedBlockPath,
20138
20299
  fragment.blocks
20139
20300
  );
20140
20301
  if (targeted) {
@@ -25010,7 +25171,7 @@ function buildFormattingDebugEntry(inputs) {
25010
25171
  }
25011
25172
 
25012
25173
  // src/runtime/layout/layout-engine-version.ts
25013
- var LAYOUT_ENGINE_VERSION = 88;
25174
+ var LAYOUT_ENGINE_VERSION = 89;
25014
25175
 
25015
25176
  // src/runtime/layout/compat-input-ledger.ts
25016
25177
  var DEFAULT_COMPATIBILITY_MODE = 15;
@@ -29695,7 +29856,7 @@ function emptyCompatibilityReport() {
29695
29856
  }
29696
29857
 
29697
29858
  // src/runtime/debug/runtime-debug-facet.ts
29698
- function createRuntimeDebugFacet(getRuntime, bus) {
29859
+ function createRuntimeDebugFacet(getRuntime, bus, options = {}) {
29699
29860
  return {
29700
29861
  bus,
29701
29862
  getSnapshot(query) {
@@ -29713,7 +29874,318 @@ function createRuntimeDebugFacet(getRuntime, bus) {
29713
29874
  },
29714
29875
  getChannels() {
29715
29876
  return bus.getChannels();
29877
+ },
29878
+ getHotEditTraces() {
29879
+ return options.getHotEditTraces?.() ?? [];
29880
+ }
29881
+ };
29882
+ }
29883
+
29884
+ // src/runtime/hot-edit/hot-edit-trace.ts
29885
+ var HOT_EDIT_TRACE_LIMIT = 64;
29886
+ var HotEditTraceRecorder = class {
29887
+ traces = [];
29888
+ sequence = 0;
29889
+ begin(input) {
29890
+ this.sequence += 1;
29891
+ return {
29892
+ sequence: this.sequence,
29893
+ commandType: input.commandType,
29894
+ startedAtUtc: input.nowUtc,
29895
+ startedAtMs: nowMs(),
29896
+ startCounters: input.counters.snapshot()
29897
+ };
29898
+ }
29899
+ complete(pending, input) {
29900
+ const endCounters = input.counters.snapshot();
29901
+ const refreshAllCount = counterDelta(pending.startCounters, endCounters, "refresh.all");
29902
+ const patchHitCount = counterDelta(pending.startCounters, endCounters, "surface.localText.patchHit");
29903
+ const patchBudgetFallbackCount = counterDelta(
29904
+ pending.startCounters,
29905
+ endCounters,
29906
+ "surface.localText.patchBudgetFallback"
29907
+ );
29908
+ const boundedEditableTargetBuildCount = counterDelta(
29909
+ pending.startCounters,
29910
+ endCounters,
29911
+ "runtime.editableTargets.boundedBuilds"
29912
+ );
29913
+ const tier = refineTier(input.tier, {
29914
+ refreshAllCount,
29915
+ patchHitCount,
29916
+ patchBudgetFallbackCount,
29917
+ boundedEditableTargetBuildCount
29918
+ });
29919
+ const trace = {
29920
+ sequence: pending.sequence,
29921
+ startedAtUtc: pending.startedAtUtc,
29922
+ commandType: pending.commandType,
29923
+ tier,
29924
+ patchMissReason: input.patchMissReason,
29925
+ totalDurationUs: Math.max(0, Math.round((nowMs() - pending.startedAtMs) * 1e3)),
29926
+ refreshAllCount,
29927
+ patchHitCount,
29928
+ patchBudgetFallbackCount,
29929
+ boundedEditableTargetBuildCount
29930
+ };
29931
+ this.traces.push(trace);
29932
+ if (this.traces.length > HOT_EDIT_TRACE_LIMIT) {
29933
+ this.traces.splice(0, this.traces.length - HOT_EDIT_TRACE_LIMIT);
29934
+ }
29935
+ input.counters.increment(`hotEdit.tier.${trace.tier}`);
29936
+ if (trace.patchMissReason !== "none") {
29937
+ input.counters.increment(`hotEdit.patchMiss.${trace.patchMissReason}`);
29938
+ }
29939
+ return trace;
29940
+ }
29941
+ getTraces() {
29942
+ return Object.freeze([...this.traces]);
29943
+ }
29944
+ clear() {
29945
+ this.traces.splice(0, this.traces.length);
29946
+ }
29947
+ };
29948
+ function refineTier(requested, counters) {
29949
+ if (requested === "blocked") return requested;
29950
+ if (counters.refreshAllCount > 0) return "full-refresh";
29951
+ if (counters.patchBudgetFallbackCount > 0 || counters.boundedEditableTargetBuildCount > 0) {
29952
+ return "bounded-projection";
29953
+ }
29954
+ if (counters.patchHitCount > 0) return "patch";
29955
+ return requested;
29956
+ }
29957
+ function counterDelta(start, end, key) {
29958
+ return (end[key] ?? 0) - (start[key] ?? 0);
29959
+ }
29960
+ function nowMs() {
29961
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
29962
+ }
29963
+
29964
+ // src/runtime/hot-edit/surface-local-patcher.ts
29965
+ function patchSurfaceTextSegment(surface, patch) {
29966
+ const delta = patch.insertedText.length - Math.max(0, patch.to - patch.from);
29967
+ let patched = false;
29968
+ const blocks = surface.blocks.map((block) => {
29969
+ const result = patchBlock(block, patch, delta);
29970
+ if (result.patched) patched = true;
29971
+ return result.block;
29972
+ });
29973
+ if (!patched) {
29974
+ return { status: "miss", reason: "segment-not-found" };
29975
+ }
29976
+ return {
29977
+ status: "patched",
29978
+ surface: {
29979
+ ...surface,
29980
+ storySize: surface.storySize + delta,
29981
+ plainText: surface.plainText.slice(0, patch.from) + patch.insertedText + surface.plainText.slice(patch.to),
29982
+ blocks
29983
+ }
29984
+ };
29985
+ }
29986
+ function patchBlock(block, patch, delta) {
29987
+ if (patch.to < block.from) return { block, patched: false };
29988
+ if (patch.from > block.to) {
29989
+ return { block: shiftBlock(block, delta), patched: false };
29990
+ }
29991
+ switch (block.kind) {
29992
+ case "paragraph":
29993
+ return patchParagraph(block, patch, delta);
29994
+ case "sdt_block": {
29995
+ let patched = false;
29996
+ const children = block.children.map((child) => {
29997
+ const result = patchBlock(child, patch, delta);
29998
+ patched ||= result.patched;
29999
+ return result.block;
30000
+ });
30001
+ return {
30002
+ block: patched ? { ...block, to: block.to + delta, children } : block,
30003
+ patched
30004
+ };
30005
+ }
30006
+ case "table": {
30007
+ let patched = false;
30008
+ const rows = block.rows.map((row2) => ({
30009
+ ...row2,
30010
+ cells: row2.cells.map((cell) => ({
30011
+ ...cell,
30012
+ content: cell.content.map((child) => {
30013
+ const result = patchBlock(child, patch, delta);
30014
+ patched ||= result.patched;
30015
+ return result.block;
30016
+ })
30017
+ }))
30018
+ }));
30019
+ return {
30020
+ block: patched ? { ...block, to: block.to + delta, rows } : block,
30021
+ patched
30022
+ };
30023
+ }
30024
+ case "opaque_block":
30025
+ return { block, patched: false };
30026
+ }
30027
+ }
30028
+ function patchParagraph(block, patch, delta) {
30029
+ if (patch.from < block.from || patch.to > block.to) {
30030
+ return { block, patched: false };
30031
+ }
30032
+ const segmentIndex = block.segments.findIndex(
30033
+ (segment2) => segment2.kind === "text" && patch.from >= segment2.from && patch.to <= segment2.to
30034
+ );
30035
+ if (segmentIndex < 0) return { block, patched: false };
30036
+ const segment = block.segments[segmentIndex];
30037
+ if (segment.kind !== "text") return { block, patched: false };
30038
+ const localFrom = patch.from - segment.from;
30039
+ const localTo = patch.to - segment.from;
30040
+ const segments = block.segments.map((candidate, index) => {
30041
+ if (index < segmentIndex) return candidate;
30042
+ if (index === segmentIndex) {
30043
+ return {
30044
+ ...segment,
30045
+ text: segment.text.slice(0, localFrom) + patch.insertedText + segment.text.slice(localTo),
30046
+ to: segment.to + delta
30047
+ };
30048
+ }
30049
+ return shiftInlineSegment(candidate, delta);
30050
+ });
30051
+ return {
30052
+ block: {
30053
+ ...block,
30054
+ to: block.to + delta,
30055
+ segments
30056
+ },
30057
+ patched: true
30058
+ };
30059
+ }
30060
+ function shiftBlock(block, delta) {
30061
+ if (delta === 0) return block;
30062
+ switch (block.kind) {
30063
+ case "paragraph":
30064
+ return {
30065
+ ...block,
30066
+ from: block.from + delta,
30067
+ to: block.to + delta,
30068
+ segments: block.segments.map((segment) => shiftInlineSegment(segment, delta))
30069
+ };
30070
+ case "sdt_block":
30071
+ return {
30072
+ ...block,
30073
+ from: block.from + delta,
30074
+ to: block.to + delta,
30075
+ children: block.children.map((child) => shiftBlock(child, delta))
30076
+ };
30077
+ case "table":
30078
+ return {
30079
+ ...block,
30080
+ from: block.from + delta,
30081
+ to: block.to + delta,
30082
+ rows: block.rows.map((row2) => ({
30083
+ ...row2,
30084
+ cells: row2.cells.map((cell) => ({
30085
+ ...cell,
30086
+ content: cell.content.map((child) => shiftBlock(child, delta))
30087
+ }))
30088
+ }))
30089
+ };
30090
+ case "opaque_block":
30091
+ return {
30092
+ ...block,
30093
+ from: block.from + delta,
30094
+ to: block.to + delta
30095
+ };
30096
+ }
30097
+ }
30098
+ function shiftInlineSegment(segment, delta) {
30099
+ if (delta === 0) return segment;
30100
+ return {
30101
+ ...segment,
30102
+ from: segment.from + delta,
30103
+ to: segment.to + delta
30104
+ };
30105
+ }
30106
+
30107
+ // src/runtime/hot-edit/hot-edit-profiler.ts
30108
+ var HEAVY_REVIEW_ITEM_THRESHOLD = 24;
30109
+ var DENSE_BLOCK_NODE_THRESHOLD = 256;
30110
+ function deriveHotEditDocumentProfile(document2) {
30111
+ const blocks = document2.content.children ?? [];
30112
+ let tableBlockCount = 0;
30113
+ let maxNestedSurfaceNodesPerBlock = 0;
30114
+ for (const block of blocks) {
30115
+ if (block.type === "table") tableBlockCount += 1;
30116
+ maxNestedSurfaceNodesPerBlock = Math.max(
30117
+ maxNestedSurfaceNodesPerBlock,
30118
+ countBlockNodes(block)
30119
+ );
30120
+ }
30121
+ const commentCount = Object.keys(document2.review.comments ?? {}).length;
30122
+ const revisionCount = Object.keys(document2.review.revisions ?? {}).length;
30123
+ const secondaryStoryBlockCount = countSecondaryStoryBlocks(document2);
30124
+ return {
30125
+ blockCount: blocks.length,
30126
+ tableBlockCount,
30127
+ maxNestedSurfaceNodesPerBlock,
30128
+ commentCount,
30129
+ revisionCount,
30130
+ secondaryStoryBlockCount,
30131
+ hasHeavyReview: commentCount + revisionCount >= HEAVY_REVIEW_ITEM_THRESHOLD,
30132
+ hasDenseTables: tableBlockCount > 0 && maxNestedSurfaceNodesPerBlock > DENSE_BLOCK_NODE_THRESHOLD
30133
+ };
30134
+ }
30135
+ function countBlockNodes(block) {
30136
+ const value = block;
30137
+ let total = 1;
30138
+ if (Array.isArray(value.children)) {
30139
+ total += value.children.length;
30140
+ for (const child of value.children) {
30141
+ if (isBlockLike(child)) total += countBlockNodes(child);
29716
30142
  }
30143
+ }
30144
+ if (Array.isArray(value.rows)) {
30145
+ for (const row2 of value.rows) {
30146
+ total += 1;
30147
+ for (const cell of row2.cells ?? []) {
30148
+ total += 1;
30149
+ for (const child of cell.children ?? []) {
30150
+ total += countBlockNodes(child);
30151
+ }
30152
+ }
30153
+ }
30154
+ }
30155
+ return total;
30156
+ }
30157
+ function isBlockLike(value) {
30158
+ return Boolean(value && typeof value === "object" && "type" in value);
30159
+ }
30160
+ function countSecondaryStoryBlocks(document2) {
30161
+ const subParts = document2.subParts;
30162
+ if (!subParts) return 0;
30163
+ let count = 0;
30164
+ for (const value of Object.values(subParts)) {
30165
+ count += countBlocksInUnknownStory(value);
30166
+ }
30167
+ return count;
30168
+ }
30169
+ function countBlocksInUnknownStory(value) {
30170
+ if (!value || typeof value !== "object") return 0;
30171
+ const candidate = value;
30172
+ if (Array.isArray(candidate.children)) return candidate.children.length;
30173
+ if (Array.isArray(candidate.content?.children)) return candidate.content.children.length;
30174
+ return Object.values(value).reduce((total, entry) => total + countBlocksInUnknownStory(entry), 0);
30175
+ }
30176
+
30177
+ // src/runtime/hot-edit/hot-edit-policy.ts
30178
+ var DEFAULT_MAX_SHIFTED_SURFACE_NODES = 5e3;
30179
+ var DEFAULT_MAX_SHIFTED_NODES_PER_BLOCK = 256;
30180
+ var DEFAULT_SELECTION_CORRIDOR_BLOCK_RADIUS = 8;
30181
+ var HEAVY_DOCUMENT_SELECTION_CORRIDOR_BLOCK_RADIUS = 12;
30182
+ function resolveHotEditPolicy(profile) {
30183
+ const complexGeometry = profile.hasDenseTables || profile.secondaryStoryBlockCount > 0;
30184
+ return {
30185
+ maxShiftedSurfaceNodes: DEFAULT_MAX_SHIFTED_SURFACE_NODES,
30186
+ maxShiftedNodesPerBlock: DEFAULT_MAX_SHIFTED_NODES_PER_BLOCK,
30187
+ selectionCorridorBlockRadius: complexGeometry ? HEAVY_DOCUMENT_SELECTION_CORRIDOR_BLOCK_RADIUS : DEFAULT_SELECTION_CORRIDOR_BLOCK_RADIUS,
30188
+ preferBoundedProjectionForDenseTails: profile.hasDenseTables
29717
30189
  };
29718
30190
  }
29719
30191
 
@@ -32943,6 +33415,12 @@ function resolveScopeRange(entry, handle, positionMap) {
32943
33415
  if (inlineRange) return inlineRange;
32944
33416
  return positionMap.blocks.get(entry.blockIndex) ?? null;
32945
33417
  }
33418
+ case "image": {
33419
+ const key = `${entry.blockIndex}:${entry.inlineIndex}`;
33420
+ const inlineRange = positionMap.inlines.get(key);
33421
+ if (inlineRange) return inlineRange;
33422
+ return positionMap.blocks.get(entry.blockIndex) ?? null;
33423
+ }
32946
33424
  case "comment-thread":
32947
33425
  return anchorToRange(entry.thread.anchor);
32948
33426
  case "revision":
@@ -33081,6 +33559,11 @@ function deriveReplaceability(kind, provenance) {
33081
33559
  level: "preserve-only",
33082
33560
  reason: "field-result-is-computed-preserve-only"
33083
33561
  };
33562
+ case "image":
33563
+ return {
33564
+ level: "preserve-only",
33565
+ reason: "image-object-command-required"
33566
+ };
33084
33567
  case "comment-thread":
33085
33568
  return {
33086
33569
  level: "preserve-only",
@@ -33785,6 +34268,55 @@ function compileHeadingScope(entry, options = {}) {
33785
34268
  };
33786
34269
  }
33787
34270
 
34271
+ // src/runtime/scopes/scope-kinds/image.ts
34272
+ function imageAltText(image) {
34273
+ if (image.type === "image") return image.altText ?? "";
34274
+ return image.anchor.docPr?.descr ?? image.anchor.docPr?.name ?? "";
34275
+ }
34276
+ function imageMediaId(image) {
34277
+ if (image.type === "image") return image.mediaId;
34278
+ return image.content.type === "picture" ? image.content.mediaId : void 0;
34279
+ }
34280
+ function imageDisplay(image) {
34281
+ if (image.type === "image") return image.display;
34282
+ return image.anchor.display;
34283
+ }
34284
+ function imageSourceKind(image) {
34285
+ return image.type === "image" ? "legacy-image" : "drawing-picture";
34286
+ }
34287
+ function compileImageScope(entry) {
34288
+ const { handle, image } = entry;
34289
+ const altText = imageAltText(image);
34290
+ const mediaId = imageMediaId(image);
34291
+ const display = imageDisplay(image);
34292
+ const sourceKind = imageSourceKind(image);
34293
+ return {
34294
+ handle,
34295
+ kind: "image",
34296
+ classifications: entry.classifications,
34297
+ content: {
34298
+ text: altText,
34299
+ excerpt: buildExcerpt(altText),
34300
+ authority: "structural-summary"
34301
+ },
34302
+ formatting: {},
34303
+ layout: display ? { flowKind: display } : {},
34304
+ geometry: {},
34305
+ workflow: { scopeIds: [], effectiveMode: "edit" },
34306
+ replaceability: deriveReplaceability("image", handle.provenance),
34307
+ audit: {
34308
+ source: "runtime",
34309
+ derivedFrom: [
34310
+ "canonical",
34311
+ `image-source:${sourceKind}`,
34312
+ ...mediaId ? [`media-id:${mediaId}`] : []
34313
+ ],
34314
+ confidence: "medium"
34315
+ },
34316
+ partial: true
34317
+ };
34318
+ }
34319
+
33788
34320
  // src/runtime/scopes/scope-kinds/list-item.ts
33789
34321
  function compileListItemScope(entry, options = {}) {
33790
34322
  const { handle, paragraph } = entry;
@@ -34373,6 +34905,8 @@ function compileScope(entry, optionsOrCatalog) {
34373
34905
  });
34374
34906
  case "field":
34375
34907
  return compileFieldScope(entry);
34908
+ case "image":
34909
+ return compileImageScope(entry);
34376
34910
  case "comment-thread":
34377
34911
  return compileCommentThreadScope(entry);
34378
34912
  case "revision":
@@ -34561,6 +35095,44 @@ function enumerateFieldsInParagraph(paragraph, blockIndex, documentId, parentSco
34561
35095
  }
34562
35096
  return out;
34563
35097
  }
35098
+ function isImageInline(child) {
35099
+ return child.type === "image" || child.type === "drawing_frame" && child.content.type === "picture";
35100
+ }
35101
+ function enumerateImagesInParagraph(paragraph, blockIndex, documentId, parentScopeId) {
35102
+ const out = [];
35103
+ for (let i = 0; i < paragraph.children.length; i += 1) {
35104
+ const child = paragraph.children[i];
35105
+ if (!isImageInline(child)) continue;
35106
+ const semanticPath = [
35107
+ "body",
35108
+ "paragraph",
35109
+ String(blockIndex),
35110
+ "image",
35111
+ String(i)
35112
+ ];
35113
+ const scopeId = `image:${blockIndex}:${i}`;
35114
+ const handle = {
35115
+ scopeId,
35116
+ documentId,
35117
+ storyTarget: MAIN_STORY2,
35118
+ semanticPath,
35119
+ parentScopeId,
35120
+ stableRef: { kind: "semantic-path", value: semanticPath.join("/") },
35121
+ provenance: "derived",
35122
+ rangePrecision: "canonical"
35123
+ };
35124
+ out.push({
35125
+ kind: "image",
35126
+ handle,
35127
+ image: child,
35128
+ paragraph,
35129
+ blockIndex,
35130
+ inlineIndex: i,
35131
+ classifications: Object.freeze([])
35132
+ });
35133
+ }
35134
+ return out;
35135
+ }
34564
35136
  function enumerateCommentThreads(document2, documentId) {
34565
35137
  const review = document2.review;
34566
35138
  const comments = review?.comments;
@@ -34691,6 +35263,8 @@ function enumerateScopes(document2, inputs = {}) {
34691
35263
  });
34692
35264
  const fields = enumerateFieldsInParagraph(block, index, documentId, scopeId);
34693
35265
  for (const field of fields) results.push(field);
35266
+ const images = enumerateImagesInParagraph(block, index, documentId, scopeId);
35267
+ for (const image of images) results.push(image);
34694
35268
  continue;
34695
35269
  }
34696
35270
  if (block.type === "table") {
@@ -35080,6 +35654,15 @@ var LIST_TEXT_TARGET_KINDS = /* @__PURE__ */ new Set([
35080
35654
  "sdt-paragraph-text",
35081
35655
  "secondary-story-paragraph-text"
35082
35656
  ]);
35657
+ var OBJECT_COMMAND_INTENTS = /* @__PURE__ */ new Set([
35658
+ "image-layout",
35659
+ "image-frame",
35660
+ "chart-edit",
35661
+ "custom-xml-update",
35662
+ "embedded-content-update",
35663
+ "opaque-content-preserve",
35664
+ "object-edit"
35665
+ ]);
35083
35666
  function freezeList(values) {
35084
35667
  return Object.freeze([...values]);
35085
35668
  }
@@ -35624,6 +36207,35 @@ function listStructureCapability(scope, context) {
35624
36207
  ]
35625
36208
  );
35626
36209
  }
36210
+ function objectEditCapability(context) {
36211
+ const objectTargets = (context?.editableTargets?.entries ?? []).filter(
36212
+ (entry) => entry.kind === "object-anchor" || entry.kind === "custom-xml-content" || entry.kind === "opaque-content" || entry.commandFamily === "object" || entry.commandFamily === "preserve-only-refusal" || entry.runtimeCommand.intents.some((intent) => OBJECT_COMMAND_INTENTS.has(intent))
36213
+ );
36214
+ const supportedTargets = objectTargets.filter(
36215
+ (entry) => entry.runtimeCommand.status === "supported" && entry.runtimeCommand.intents.some((intent) => OBJECT_COMMAND_INTENTS.has(intent))
36216
+ );
36217
+ if (supportedTargets.length > 0) {
36218
+ return supportedCommand(
36219
+ "compile-supported:object-edit:editable-target",
36220
+ supportedTargets
36221
+ );
36222
+ }
36223
+ if (objectTargets.length > 0) {
36224
+ const blockers = commandTargetBlockers(objectTargets);
36225
+ return blocked(
36226
+ "compile-blocked:object-edit:target-ref-blocked",
36227
+ blockers.length > 0 ? blockers : ["compile-blocked:object-edit:target-ref-blocked"]
36228
+ );
36229
+ }
36230
+ return unsupported(
36231
+ "compile-unsupported:object-edit:no-target-family",
36232
+ [
36233
+ "compile-unsupported:object-edit:no-target-family",
36234
+ "capability:object-edit:l02-object-target-required",
36235
+ "capability:object-edit:l07-command-support-required"
36236
+ ]
36237
+ );
36238
+ }
35627
36239
  function deriveScopeCapabilities(scope, context = {}) {
35628
36240
  return {
35629
36241
  canReplaceText: replaceTextCapability(scope, context),
@@ -35640,7 +36252,8 @@ function deriveScopeCapabilities(scope, context = {}) {
35640
36252
  canEditTableStructure: tableStructureCapability(scope, context),
35641
36253
  canUseTableContinuationEvidence: tableContinuationEvidenceCapability(scope, context),
35642
36254
  canEditListText: listTextCapability(scope, context),
35643
- canEditListStructure: listStructureCapability(scope, context)
36255
+ canEditListStructure: listStructureCapability(scope, context),
36256
+ canEditObject: objectEditCapability(context)
35644
36257
  };
35645
36258
  }
35646
36259
 
@@ -35912,6 +36525,11 @@ function tokensForScope(entry) {
35912
36525
  { kind: "row", index: entry.rowIndex },
35913
36526
  { kind: "cell", index: entry.cellIndex }
35914
36527
  ]);
36528
+ case "image":
36529
+ return Object.freeze([
36530
+ { kind: "block", index: entry.blockIndex },
36531
+ { kind: "inline", index: entry.inlineIndex }
36532
+ ]);
35915
36533
  default:
35916
36534
  return null;
35917
36535
  }
@@ -36659,6 +37277,64 @@ function deriveScopeEditableTargetEvidence(document2, scope, entry, options = {}
36659
37277
  };
36660
37278
  }
36661
37279
 
37280
+ // src/runtime/scopes/object-evidence.ts
37281
+ var OBJECT_INTENTS = /* @__PURE__ */ new Set([
37282
+ "image-layout",
37283
+ "image-frame",
37284
+ "chart-edit",
37285
+ "custom-xml-update",
37286
+ "embedded-content-update",
37287
+ "opaque-content-preserve",
37288
+ "object-edit",
37289
+ "preserve-only-refusal"
37290
+ ]);
37291
+ function unique2(values) {
37292
+ return Object.freeze([...new Set(values.filter((value) => value.length > 0))]);
37293
+ }
37294
+ function isObjectTarget(entry) {
37295
+ return entry.object !== void 0 || entry.kind === "object-anchor" || entry.kind === "custom-xml-content" || entry.kind === "opaque-content" || entry.commandFamily === "object" || entry.runtimeCommand.intents.some((intent) => OBJECT_INTENTS.has(intent));
37296
+ }
37297
+ function blockersFor(entry) {
37298
+ return unique2([
37299
+ ...entry.posture.blockers,
37300
+ ...entry.runtimeCommand.blockers ?? [],
37301
+ ...entry.runtimeTextCommand.blockers ?? [],
37302
+ ...(entry.workflowBlockers ?? []).flatMap((blocker) => [
37303
+ blocker.blocker,
37304
+ blocker.refusalId
37305
+ ]),
37306
+ entry.runtimeCommand.status === "blocked" ? entry.runtimeCommand.reason : ""
37307
+ ]);
37308
+ }
37309
+ function projectEntry2(entry) {
37310
+ const blockers = blockersFor(entry);
37311
+ return {
37312
+ targetKey: entry.targetKey,
37313
+ kind: entry.kind,
37314
+ ...entry.object?.objectKind ? { objectKind: entry.object.objectKind } : {},
37315
+ relation: entry.relation,
37316
+ commandFamily: entry.commandFamily,
37317
+ editability: entry.editability,
37318
+ ...entry.sourceRef ? { sourceRef: entry.sourceRef } : {},
37319
+ ...entry.object ? { object: entry.object } : {},
37320
+ runtimeCommand: entry.runtimeCommand,
37321
+ blockers,
37322
+ ...entry.posture.preserveOnly ? { preserveOnly: true } : {}
37323
+ };
37324
+ }
37325
+ function deriveScopeObjectEvidence(editableTargets) {
37326
+ const entries = Object.freeze(
37327
+ [...editableTargets?.entries ?? []].filter(isObjectTarget).map(projectEntry2).sort((left, right) => left.targetKey.localeCompare(right.targetKey))
37328
+ );
37329
+ const blockers = unique2(entries.flatMap((entry) => [...entry.blockers]));
37330
+ return {
37331
+ status: entries.length > 0 ? "present" : "none",
37332
+ count: entries.length,
37333
+ blockers,
37334
+ entries
37335
+ };
37336
+ }
37337
+
36662
37338
  // src/runtime/scopes/table-evidence.ts
36663
37339
  function isTableFamilyEntry(entry) {
36664
37340
  return entry?.kind === "table" || entry?.kind === "table-row" || entry?.kind === "table-cell";
@@ -37228,7 +37904,7 @@ function deriveScopeGeometryEvidence(scopeId, provider, context) {
37228
37904
  function freezeList2(values) {
37229
37905
  return values ? Object.freeze([...values]) : void 0;
37230
37906
  }
37231
- function unique2(values) {
37907
+ function unique3(values) {
37232
37908
  return Object.freeze([...new Set(values)]);
37233
37909
  }
37234
37910
  function parseTableFamilyScopeId2(scopeId) {
@@ -37258,7 +37934,7 @@ function candidateTableBlockIds(blockIndex, mapped) {
37258
37934
  const mappedId = mapped?.get(blockIndex);
37259
37935
  if (mappedId) ids.push(mappedId);
37260
37936
  ids.push(`table-${blockIndex}`, `table:${blockIndex}`, `block-${blockIndex}`);
37261
- return unique2(ids);
37937
+ return unique3(ids);
37262
37938
  }
37263
37939
  function rowInFragment(fragment, rowIndex) {
37264
37940
  const range = fragment.tableRowRange;
@@ -37295,19 +37971,19 @@ function projectTableFramePage(fragment) {
37295
37971
  ...fragment.tableRowRange ? { rowRange: { ...fragment.tableRowRange } } : {},
37296
37972
  ...fragment.continuation?.continuesFromPreviousPage !== void 0 ? { continuesFromPreviousPage: fragment.continuation.continuesFromPreviousPage } : {},
37297
37973
  ...fragment.continuation?.continuesToNextPage !== void 0 ? { continuesToNextPage: fragment.continuation.continuesToNextPage } : {},
37298
- ...repeated ? { repeatedHeaderRowIndexes: unique2(repeated) } : {},
37974
+ ...repeated ? { repeatedHeaderRowIndexes: unique3(repeated) } : {},
37299
37975
  ...splitRowCarry ? { splitRowCarry: Object.freeze(splitRowCarry.map((item) => ({ ...item }))) } : {},
37300
37976
  ...carry ? { verticalMergeCarry: Object.freeze(carry.map((item) => ({ ...item }))) } : {}
37301
37977
  };
37302
37978
  }
37303
37979
  function projectTableFrame(blockId, parsed, fragments) {
37304
- const pageIds = unique2(fragments.map((fragment) => fragment.pageId));
37305
- const pageSliceIds = unique2(fragments.map((fragment) => fragment.fragmentId));
37306
- const layoutObjectIds = unique2(
37980
+ const pageIds = unique3(fragments.map((fragment) => fragment.pageId));
37981
+ const pageSliceIds = unique3(fragments.map((fragment) => fragment.fragmentId));
37982
+ const layoutObjectIds = unique3(
37307
37983
  fragments.map((fragment) => fragment.layoutObject?.objectId).filter((objectId) => typeof objectId === "string" && objectId.length > 0)
37308
37984
  );
37309
37985
  const rowRangesByPage = Object.freeze(fragments.map(projectTableFramePage));
37310
- const repeatedHeaderRowIndexes = unique2(
37986
+ const repeatedHeaderRowIndexes = unique3(
37311
37987
  fragments.flatMap((fragment) => fragment.continuation?.repeatedHeaderRowIndexes ?? [])
37312
37988
  );
37313
37989
  const verticalMergeCarry = Object.freeze(
@@ -37332,7 +38008,7 @@ function projectTableFrame(blockId, parsed, fragments) {
37332
38008
  };
37333
38009
  }
37334
38010
  function continuationFromTableFrame(fragments) {
37335
- const pageIds = unique2(fragments.map((fragment) => fragment.pageId));
38011
+ const pageIds = unique3(fragments.map((fragment) => fragment.pageId));
37336
38012
  return {
37337
38013
  ...pageIds.length > 0 ? { pageIds } : {},
37338
38014
  pageCount: pageIds.length,
@@ -37630,6 +38306,7 @@ function composeEvidence(inputs) {
37630
38306
  ...editableTargets ? { editableTargets } : {},
37631
38307
  layout
37632
38308
  });
38309
+ const objects = deriveScopeObjectEvidence(editableTargets);
37633
38310
  return {
37634
38311
  formattingSummary: formattingSummaryOf(scope),
37635
38312
  reviewItemIds,
@@ -37640,6 +38317,7 @@ function composeEvidence(inputs) {
37640
38317
  ...adjacentGeometry ? { adjacentGeometry } : {},
37641
38318
  visualization: deriveScopeVisualization(scope),
37642
38319
  ...editableTargets ? { editableTargets } : {},
38320
+ objects,
37643
38321
  ...table ? { table } : {},
37644
38322
  contentControls,
37645
38323
  capabilities,
@@ -42492,6 +43170,14 @@ function paginateSectionBlocksWithSplits(section, blocks, layout, footnotes, mea
42492
43170
  pushPage(block.from);
42493
43171
  continue;
42494
43172
  }
43173
+ if (isStandalonePageBreakParagraph(block)) {
43174
+ if (columnHeight > 0) {
43175
+ pushPage(nextBoundary);
43176
+ } else {
43177
+ pageStart = Math.max(pageStart, Math.min(nextBoundary, section.end));
43178
+ }
43179
+ break;
43180
+ }
42495
43181
  const effectiveNoteHeight = estimateFootnoteReservation(
42496
43182
  block,
42497
43183
  footnotes,
@@ -42666,6 +43352,21 @@ function hasPageBreak(block) {
42666
43352
  }
42667
43353
  return nestedBlocks(block).some(hasPageBreak);
42668
43354
  }
43355
+ function isStandalonePageBreakParagraph(block) {
43356
+ if (block.kind !== "paragraph") return false;
43357
+ let sawPageBreak = false;
43358
+ for (const segment of block.segments) {
43359
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
43360
+ sawPageBreak = true;
43361
+ continue;
43362
+ }
43363
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
43364
+ continue;
43365
+ }
43366
+ return false;
43367
+ }
43368
+ return sawPageBreak;
43369
+ }
42669
43370
  function nestedBlocks(block) {
42670
43371
  if (block.kind === "sdt_block") {
42671
43372
  return block.children;
@@ -44150,6 +44851,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
44150
44851
  for (let blockIndex = 0; blockIndex < surface.blocks.length; blockIndex += 1) {
44151
44852
  const block = surface.blocks[blockIndex];
44152
44853
  const blockPath = `main/block[${blockIndex}]`;
44854
+ if (isStandalonePageBreakParagraph2(block)) {
44855
+ continue;
44856
+ }
44153
44857
  if (block.kind === "table") {
44154
44858
  const tableSliceList = splits?.tablesByBlockId.get(block.blockId);
44155
44859
  if (tableSliceList && tableSliceList.length > 1) {
@@ -44235,6 +44939,23 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
44235
44939
  }
44236
44940
  return byPage;
44237
44941
  }
44942
+ function isStandalonePageBreakParagraph2(block) {
44943
+ if (block.kind !== "paragraph") {
44944
+ return false;
44945
+ }
44946
+ let sawPageBreak = false;
44947
+ for (const segment of block.segments) {
44948
+ if (segment.kind === "opaque_inline" && segment.label === "Page break") {
44949
+ sawPageBreak = true;
44950
+ continue;
44951
+ }
44952
+ if (segment.kind === "text" && segment.text.trim().length === 0) {
44953
+ continue;
44954
+ }
44955
+ return false;
44956
+ }
44957
+ return sawPageBreak;
44958
+ }
44238
44959
  function projectLineBoxesForPageFragments(pages, fragmentsByPageIndex, fragmentMeasurementsByPageIndex, surface) {
44239
44960
  const byPage = /* @__PURE__ */ new Map();
44240
44961
  const blocksById = surface ? new Map(surface.blocks.map((block) => [block.blockId, block])) : /* @__PURE__ */ new Map();
@@ -44747,13 +45468,11 @@ function buildBookmarkRanges(targets) {
44747
45468
  }
44748
45469
  var EMPTY_NUMBERING_INPUT_INDEX = {
44749
45470
  byNumberingKey: /* @__PURE__ */ new Map(),
44750
- byBlockPath: /* @__PURE__ */ new Map(),
44751
- byParagraphIndex: /* @__PURE__ */ new Map()
45471
+ byBlockPath: /* @__PURE__ */ new Map()
44752
45472
  };
44753
45473
  function buildNumberingInputIndex(numberingInputs) {
44754
45474
  const byNumberingKey = /* @__PURE__ */ new Map();
44755
45475
  const byBlockPath = /* @__PURE__ */ new Map();
44756
- const byParagraph = /* @__PURE__ */ new Map();
44757
45476
  for (const input of numberingInputs) {
44758
45477
  if (!byNumberingKey.has(input.numberingKey)) {
44759
45478
  byNumberingKey.set(input.numberingKey, input);
@@ -44761,11 +45480,8 @@ function buildNumberingInputIndex(numberingInputs) {
44761
45480
  if (!byBlockPath.has(input.blockPath)) {
44762
45481
  byBlockPath.set(input.blockPath, input);
44763
45482
  }
44764
- if (!byParagraph.has(input.paragraphIndex)) {
44765
- byParagraph.set(input.paragraphIndex, input);
44766
- }
44767
45483
  }
44768
- return { byNumberingKey, byBlockPath, byParagraphIndex: byParagraph };
45484
+ return { byNumberingKey, byBlockPath };
44769
45485
  }
44770
45486
  function collectBookmarkRangeLayoutFacts(fragmentId, blockPath, bookmarkRanges) {
44771
45487
  if (!blockPath || !bookmarkRanges || bookmarkRanges.length === 0) return [];
@@ -44885,8 +45601,7 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingIndex, n
44885
45601
  const canonical = lookupNumberingInput(
44886
45602
  numberingIndex,
44887
45603
  numberingKey,
44888
- context.path,
44889
- paragraphIndex
45604
+ context.path
44890
45605
  );
44891
45606
  const target = findNumberingTarget(numberingTargets, context.path);
44892
45607
  const numberingLayoutId = numberingKey ?? [
@@ -44926,7 +45641,7 @@ function findNumberingTarget(numberingTargets, blockPath) {
44926
45641
  if (blockPath === void 0) return void 0;
44927
45642
  return numberingTargets.find((target) => target.blockPath === blockPath);
44928
45643
  }
44929
- function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraphIndex) {
45644
+ function lookupNumberingInput(numberingIndex, numberingKey, blockPath) {
44930
45645
  if (!numberingIndex) return void 0;
44931
45646
  if (numberingKey !== void 0) {
44932
45647
  const byKey = numberingIndex.byNumberingKey.get(numberingKey);
@@ -44936,7 +45651,7 @@ function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraph
44936
45651
  const byPath = numberingIndex.byBlockPath.get(blockPath);
44937
45652
  if (byPath !== void 0) return byPath;
44938
45653
  }
44939
- return paragraphIndex !== void 0 ? numberingIndex.byParagraphIndex.get(paragraphIndex) : void 0;
45654
+ return void 0;
44940
45655
  }
44941
45656
  function collectNumberingUnavailableReasons(numbering, canonical) {
44942
45657
  const reasons = [];
@@ -53301,8 +54016,6 @@ function sortJson2(value) {
53301
54016
 
53302
54017
  // src/runtime/document-runtime.ts
53303
54018
  var CANONICAL_BLOCK_REFS_SYMBOL2 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
53304
- var LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES = 5e3;
53305
- var LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK = 256;
53306
54019
  function getLocalTextPatchMetadata(mapping) {
53307
54020
  const metadata = mapping.metadata?.localTextPatch;
53308
54021
  if (!metadata || typeof metadata !== "object") {
@@ -53409,6 +54122,17 @@ function createDocumentRuntime(options) {
53409
54122
  const loadScheduler = options.loadScheduler ?? createLoadScheduler({ backendOverride: "sync" });
53410
54123
  let effectiveMarkupModeProvider;
53411
54124
  const perfCounters = new PerfCounters();
54125
+ const hotEditTraces = new HotEditTraceRecorder();
54126
+ let cachedHotEditPolicy = null;
54127
+ function getHotEditPolicy() {
54128
+ if (cachedHotEditPolicy?.document === state.document) {
54129
+ return cachedHotEditPolicy.policy;
54130
+ }
54131
+ const profile = deriveHotEditDocumentProfile(state.document);
54132
+ const policy = resolveHotEditPolicy(profile);
54133
+ cachedHotEditPolicy = { document: state.document, profile, policy };
54134
+ return policy;
54135
+ }
53412
54136
  let analyticsEmitScheduled = false;
53413
54137
  let analyticsEmitScheduleMode = "none";
53414
54138
  let deferNextContextAnalyticsEmit = false;
@@ -53480,7 +54204,6 @@ function createDocumentRuntime(options) {
53480
54204
  let viewportBlockRanges = null;
53481
54205
  let viewportRangesKey = serializeViewportRanges(viewportBlockRanges);
53482
54206
  let viewportBlocksPerPageEstimate = null;
53483
- const EDITING_CORRIDOR_BLOCK_RADIUS = 8;
53484
54207
  const getRuntimeForLayoutFacet = () => {
53485
54208
  if (!runtimeRef) {
53486
54209
  throw new Error("Document runtime viewport methods are not initialized");
@@ -53814,8 +54537,8 @@ function createDocumentRuntime(options) {
53814
54537
  return viewportBlockRanges;
53815
54538
  }
53816
54539
  const corridor = {
53817
- start: Math.max(0, caretBlockIndex - EDITING_CORRIDOR_BLOCK_RADIUS),
53818
- end: Math.min(previousSurface.blocks.length, caretBlockIndex + EDITING_CORRIDOR_BLOCK_RADIUS + 1)
54540
+ start: Math.max(0, caretBlockIndex - getHotEditPolicy().selectionCorridorBlockRadius),
54541
+ end: Math.min(previousSurface.blocks.length, caretBlockIndex + getHotEditPolicy().selectionCorridorBlockRadius + 1)
53819
54542
  };
53820
54543
  return normalizeViewportRanges([...viewportBlockRanges ?? [], corridor]);
53821
54544
  }
@@ -53896,8 +54619,12 @@ function createDocumentRuntime(options) {
53896
54619
  (block2) => block2.kind === "paragraph" && editFrom >= block2.from && editTo <= block2.to
53897
54620
  );
53898
54621
  if (blockIndex < 0) {
53899
- perfCounters.increment("surface.localText.patchMiss");
53900
- return null;
54622
+ return tryPatchNestedLocalTextSurface(
54623
+ previousSurface,
54624
+ editFrom,
54625
+ editTo,
54626
+ patch.insertedText
54627
+ );
53901
54628
  }
53902
54629
  const block = previousSurface.blocks[blockIndex];
53903
54630
  if (block.kind !== "paragraph") {
@@ -53972,6 +54699,34 @@ function createDocumentRuntime(options) {
53972
54699
  perfCounters.increment("surface.localText.total.us", Math.round((performance.now() - tTotal0) * 1e3));
53973
54700
  }
53974
54701
  }
54702
+ function tryPatchNestedLocalTextSurface(previousSurface, editFrom, editTo, insertedText) {
54703
+ const shiftBudget = estimateLocalTextPatchShiftBudget(previousSurface.blocks, 0);
54704
+ perfCounters.increment("surface.localText.shiftedBlocks", shiftBudget.shiftedBlocks);
54705
+ perfCounters.increment("surface.localText.shiftedNodes", shiftBudget.shiftedNodes);
54706
+ if (!shiftBudget.withinBudget) {
54707
+ perfCounters.increment("surface.localText.patchBudgetFallback");
54708
+ return null;
54709
+ }
54710
+ const patched = patchSurfaceTextSegment(previousSurface, {
54711
+ from: editFrom,
54712
+ to: editTo,
54713
+ insertedText
54714
+ });
54715
+ if (patched.status !== "patched") {
54716
+ perfCounters.increment("surface.localText.patchMiss");
54717
+ return null;
54718
+ }
54719
+ const refs = getSurfaceCanonicalBlockRefs(previousSurface);
54720
+ if (refs) {
54721
+ const nextRefs = state.document.content.children.map(
54722
+ (block, index) => block ?? refs[index] ?? null
54723
+ );
54724
+ attachSurfaceCanonicalBlockRefs(patched.surface, nextRefs);
54725
+ }
54726
+ perfCounters.increment("surface.localText.patchHit");
54727
+ perfCounters.increment("surface.localText.patchDelta", insertedText.length - (editTo - editFrom));
54728
+ return patched.surface;
54729
+ }
53975
54730
  function shiftSurfaceInlineSegment(segment, delta) {
53976
54731
  if (delta === 0) return segment;
53977
54732
  return {
@@ -54019,25 +54774,26 @@ function createDocumentRuntime(options) {
54019
54774
  }
54020
54775
  }
54021
54776
  function estimateLocalTextPatchShiftBudget(blocks, startIndex) {
54777
+ const policy = getHotEditPolicy();
54022
54778
  const shiftedBlocks = Math.max(0, blocks.length - startIndex);
54023
54779
  let shiftedNodes = 0;
54024
54780
  for (let index = startIndex; index < blocks.length; index += 1) {
54025
54781
  const shiftedBlockNodes = countSurfaceShiftNodesUpTo(
54026
54782
  blocks[index],
54027
54783
  Math.min(
54028
- LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK,
54029
- LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES - shiftedNodes
54784
+ policy.maxShiftedNodesPerBlock,
54785
+ policy.maxShiftedSurfaceNodes - shiftedNodes
54030
54786
  ) + 1
54031
54787
  );
54032
54788
  shiftedNodes += shiftedBlockNodes;
54033
- if (shiftedBlockNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK) {
54789
+ if (shiftedBlockNodes > policy.maxShiftedNodesPerBlock) {
54034
54790
  return {
54035
54791
  shiftedBlocks,
54036
54792
  shiftedNodes,
54037
54793
  withinBudget: false
54038
54794
  };
54039
54795
  }
54040
- if (shiftedNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES) {
54796
+ if (shiftedNodes > policy.maxShiftedSurfaceNodes) {
54041
54797
  return {
54042
54798
  shiftedBlocks,
54043
54799
  shiftedNodes,
@@ -55001,7 +55757,9 @@ function createDocumentRuntime(options) {
55001
55757
  });
55002
55758
  const r5ScratchReplayState = { ...state };
55003
55759
  const r5ScratchReplaySnapshot = { ...cachedRenderSnapshot };
55004
- const debugFacet = createRuntimeDebugFacet(() => runtime, telemetryBus);
55760
+ const debugFacet = createRuntimeDebugFacet(() => runtime, telemetryBus, {
55761
+ getHotEditTraces: () => hotEditTraces.getTraces()
55762
+ });
55005
55763
  function prepareTableStructureCommandForExecution(command, document2, storyTarget) {
55006
55764
  const resolution = resolveEditableTableStructureTarget({
55007
55765
  document: document2,
@@ -55094,15 +55852,16 @@ function createDocumentRuntime(options) {
55094
55852
  ...resolution.textTarget ? { textTarget: resolution.textTarget } : {}
55095
55853
  };
55096
55854
  }
55097
- function prepareFragmentInsertCommandForExecution(command, document2, surface, storyTarget) {
55855
+ function prepareFragmentInsertCommandForExecution(command, document2, surface, storyTarget, selection) {
55098
55856
  if (!command.editableTarget) {
55099
- return { kind: "accepted", selection: state.selection };
55857
+ return { kind: "accepted", selection };
55100
55858
  }
55101
55859
  const resolution = resolveEditableTextTarget({
55102
55860
  document: document2,
55103
55861
  surface,
55104
55862
  target: command.editableTarget,
55105
55863
  activeStoryKey: canonicalEditableTargetStoryKey(storyTarget),
55864
+ selection,
55106
55865
  editableTargetCache: editableTargetBlockCache
55107
55866
  });
55108
55867
  if (resolution.kind === "rejected") {
@@ -55120,7 +55879,7 @@ function createDocumentRuntime(options) {
55120
55879
  }
55121
55880
  return {
55122
55881
  kind: "accepted",
55123
- selection: createSelectionSnapshot(resolution.range.from, resolution.range.to),
55882
+ selection,
55124
55883
  ...resolution.textTarget ? { textTarget: resolution.textTarget } : {}
55125
55884
  };
55126
55885
  }
@@ -55292,7 +56051,8 @@ function createDocumentRuntime(options) {
55292
56051
  command,
55293
56052
  state.document,
55294
56053
  cachedRenderSnapshot.surface?.blocks ?? [],
55295
- activeStory
56054
+ activeStory,
56055
+ commandSelection
55296
56056
  );
55297
56057
  if (prepared.kind === "rejected") {
55298
56058
  return;
@@ -55455,7 +56215,8 @@ function createDocumentRuntime(options) {
55455
56215
  command,
55456
56216
  replayState.document,
55457
56217
  replaySnapshot.surface?.blocks ?? [],
55458
- replayStory
56218
+ replayStory,
56219
+ replayState.selection
55459
56220
  );
55460
56221
  if (prepared.kind === "rejected") {
55461
56222
  return;
@@ -55598,7 +56359,8 @@ function createDocumentRuntime(options) {
55598
56359
  command,
55599
56360
  stateForCommand.document,
55600
56361
  snapshotForCommand.surface?.blocks ?? [],
55601
- replayStory
56362
+ replayStory,
56363
+ stateForCommand.selection
55602
56364
  );
55603
56365
  if (prepared.kind === "rejected") {
55604
56366
  continue;
@@ -56162,7 +56924,7 @@ function createDocumentRuntime(options) {
56162
56924
  try {
56163
56925
  const timestamp = clock();
56164
56926
  const selection = target ? createSelectionFromPublicAnchor(target) : state.selection;
56165
- const editableTarget = editContext?.editableTarget && isTableParagraphEditableTarget(editContext.editableTarget) ? editContext.editableTarget : inferEditableTargetForFragmentInsert(
56927
+ const editableTarget = editContext?.editableTarget && isFragmentInsertEditableTarget(editContext.editableTarget) ? editContext.editableTarget : inferEditableTargetForFragmentInsert(
56166
56928
  cachedRenderSnapshot.surface?.blocks ?? [],
56167
56929
  selection
56168
56930
  );
@@ -56293,12 +57055,23 @@ function createDocumentRuntime(options) {
56293
57055
  return actionDepth > 0;
56294
57056
  },
56295
57057
  applyActiveStoryTextCommand(command) {
57058
+ const pendingHotEditTrace = hotEditTraces.begin({
57059
+ commandType: command.type,
57060
+ nowUtc: clock(),
57061
+ counters: perfCounters
57062
+ });
56296
57063
  try {
56297
- return applyTextCommandInActiveStory(command);
57064
+ const ack = applyTextCommandInActiveStory(command);
57065
+ hotEditTraces.complete(pendingHotEditTrace, {
57066
+ tier: classifyHotEditTier(ack),
57067
+ patchMissReason: classifyHotEditPatchMissReason(ack),
57068
+ counters: perfCounters
57069
+ });
57070
+ return ack;
56298
57071
  } catch (error) {
56299
57072
  const runtimeError = toRuntimeError(error);
56300
57073
  emitError(runtimeError);
56301
- return {
57074
+ const ack = {
56302
57075
  kind: "rejected",
56303
57076
  refreshClass: "blocked",
56304
57077
  opId: command.origin?.opId,
@@ -56310,6 +57083,12 @@ function createDocumentRuntime(options) {
56310
57083
  }
56311
57084
  ]
56312
57085
  };
57086
+ hotEditTraces.complete(pendingHotEditTrace, {
57087
+ tier: "blocked",
57088
+ patchMissReason: "participant-blocked",
57089
+ counters: perfCounters
57090
+ });
57091
+ return ack;
56313
57092
  }
56314
57093
  },
56315
57094
  addComment(params) {
@@ -57980,7 +58759,7 @@ function createDocumentRuntime(options) {
57980
58759
  editableTargetCache: editableTargetBlockCache,
57981
58760
  activeStorySize: cachedRenderSnapshot.surface?.storySize,
57982
58761
  textTarget,
57983
- preserveNumberingOnSplit: commandForDispatch.type === "paragraph.split" && targetResolution?.kind === "accepted" && editableTarget?.listAddress?.operationScope === "list-text",
58762
+ preserveNumberingOnSplit: (commandForDispatch.type === "paragraph.split" || commandForDispatch.type === "fragment.insert") && targetResolution?.kind === "accepted" && editableTarget?.listAddress?.operationScope === "list-text",
57984
58763
  rejectTargetlessTableStructureInsert: true
57985
58764
  };
57986
58765
  const baseState = selection === state.selection ? state : {
@@ -58085,6 +58864,27 @@ function createDocumentRuntime(options) {
58085
58864
  newRevisionToken: state.revisionToken
58086
58865
  }));
58087
58866
  }
58867
+ function classifyHotEditTier(ack) {
58868
+ if (ack.kind === "rejected" || ack.refreshClass === "blocked") {
58869
+ return "blocked";
58870
+ }
58871
+ if (ack.refreshClass === "full-projection" || ack.kind === "structural-divergence") {
58872
+ return "full-refresh";
58873
+ }
58874
+ if (ack.refreshClass === "local-text-equivalent" || ack.refreshClass === "selection-only" || ack.refreshClass === "surface-only") {
58875
+ return "patch";
58876
+ }
58877
+ return "full-refresh";
58878
+ }
58879
+ function classifyHotEditPatchMissReason(ack) {
58880
+ if (ack.kind === "rejected" || ack.refreshClass === "blocked") {
58881
+ return "participant-blocked";
58882
+ }
58883
+ if (ack.refreshClass === "full-projection" || ack.kind === "structural-divergence") {
58884
+ return "effect-disqualified";
58885
+ }
58886
+ return "none";
58887
+ }
58088
58888
  function classifyAck(params) {
58089
58889
  const { opId, priorState, transaction, newRevisionToken } = params;
58090
58890
  const meta = transaction.mapping.metadata ?? {};
@@ -58802,7 +59602,7 @@ function canonicalEditableTargetStoryKey(storyTarget) {
58802
59602
  function inferEditableTargetForFragmentInsert(blocks, selection) {
58803
59603
  const position = Math.min(selection.anchor, selection.head);
58804
59604
  const target = findEditableTargetAtSurfacePosition(blocks, position);
58805
- return target && isTableParagraphEditableTarget(target) ? target : void 0;
59605
+ return target && isFragmentInsertEditableTarget(target) ? target : void 0;
58806
59606
  }
58807
59607
  function findEditableTargetAtSurfacePosition(blocks, position) {
58808
59608
  for (const block of blocks) {
@@ -58831,8 +59631,14 @@ function findEditableTargetInSurfaceCell(cell, position) {
58831
59631
  }
58832
59632
  return findEditableTargetAtSurfacePosition(cell.content, position);
58833
59633
  }
58834
- function isTableParagraphEditableTarget(target) {
58835
- return target.editability === "editable" && target.posture.blockers.length === 0 && target.commandFamily === "text-leaf" && (target.kind === "table-cell-paragraph-text" || target.kind === "nested-table-cell-paragraph-text" || target.kind === "sdt-table-cell-paragraph-text");
59634
+ function isFragmentInsertEditableTarget(target) {
59635
+ if (target.editability !== "editable" || target.posture.blockers.length > 0 || target.commandFamily !== "text-leaf") {
59636
+ return false;
59637
+ }
59638
+ if (target.listAddress?.operationScope === "list-text") {
59639
+ return true;
59640
+ }
59641
+ return target.kind === "table-cell-paragraph-text" || target.kind === "nested-table-cell-paragraph-text" || target.kind === "sdt-table-cell-paragraph-text";
58836
59642
  }
58837
59643
  function extractSelectionFragment(document2, selection, activeStory) {
58838
59644
  const from = Math.min(selection.anchor, selection.head);