@beyondwork/docx-react-component 1.0.66 → 1.0.69

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 (384) hide show
  1. package/README.md +75 -931
  2. package/package.json +26 -27
  3. package/src/api/anchor-conversion.ts +43 -0
  4. package/src/api/editor-state-types.ts +2 -1
  5. package/src/api/public-types.ts +504 -101
  6. package/src/api/session-state.ts +4 -0
  7. package/src/api/v3/README.md +91 -0
  8. package/src/api/v3/_create.ts +146 -0
  9. package/src/api/v3/_layer-metadata.ts +362 -0
  10. package/src/api/v3/_mocks.ts +84 -0
  11. package/src/api/v3/_runtime-handle.ts +162 -0
  12. package/src/api/v3/_ux-response.ts +73 -0
  13. package/src/api/v3/ai/_metadata-audit.ts +225 -0
  14. package/src/api/v3/ai/attach.ts +235 -0
  15. package/src/api/v3/ai/bundle.ts +132 -0
  16. package/src/api/v3/ai/explain.ts +144 -0
  17. package/src/api/v3/ai/export.ts +54 -0
  18. package/src/api/v3/ai/inspect.ts +118 -0
  19. package/src/api/v3/ai/policy.ts +77 -0
  20. package/src/api/v3/ai/replacement.ts +341 -0
  21. package/src/api/v3/ai/resolve.ts +133 -0
  22. package/src/api/v3/index.ts +79 -0
  23. package/src/api/v3/runtime/chart.ts +310 -0
  24. package/src/api/v3/runtime/clipboard.ts +81 -0
  25. package/src/api/v3/runtime/collab.ts +331 -0
  26. package/src/api/v3/runtime/content.ts +236 -0
  27. package/src/api/v3/runtime/document.ts +282 -0
  28. package/src/api/v3/runtime/formatting.ts +186 -0
  29. package/src/api/v3/runtime/geometry.ts +349 -0
  30. package/src/api/v3/runtime/layout.ts +108 -0
  31. package/src/api/v3/runtime/review.ts +129 -0
  32. package/src/api/v3/runtime/search.ts +74 -0
  33. package/src/api/v3/runtime/table.ts +63 -0
  34. package/src/api/v3/runtime/workflow.ts +434 -0
  35. package/src/api/v3/ui/_context.ts +86 -0
  36. package/src/api/v3/ui/_create.ts +65 -0
  37. package/src/api/v3/ui/_types.ts +520 -0
  38. package/src/api/v3/ui/chrome-composition.ts +342 -0
  39. package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
  40. package/src/api/v3/ui/chrome.ts +476 -0
  41. package/src/api/v3/ui/debug.ts +124 -0
  42. package/src/api/v3/ui/index.ts +64 -0
  43. package/src/api/v3/ui/overlays-visibility.ts +170 -0
  44. package/src/api/v3/ui/overlays.ts +427 -0
  45. package/src/api/v3/ui/scope.ts +71 -0
  46. package/src/api/v3/ui/session.ts +100 -0
  47. package/src/api/v3/ui/surface.ts +170 -0
  48. package/src/api/v3/ui/viewport.ts +303 -0
  49. package/src/core/commands/index.ts +28 -6
  50. package/src/core/commands/list-commands.ts +3 -2
  51. package/src/core/commands/section-layout-commands.ts +9 -8
  52. package/src/core/schema/text-schema.ts +16 -0
  53. package/src/core/selection/mapping.ts +33 -72
  54. package/src/core/state/editor-state.ts +96 -189
  55. package/src/index.ts +23 -4
  56. package/src/io/chart-preview-resolver.ts +1 -1
  57. package/src/io/docx-session.ts +36 -4795
  58. package/src/io/export/build-app-properties-xml.ts +1 -1
  59. package/src/io/export/serialize-comments.ts +1 -1
  60. package/src/io/export/serialize-headers-footers.ts +6 -1
  61. package/src/io/export/serialize-main-document.ts +45 -0
  62. package/src/io/export/serialize-run-formatting.ts +17 -2
  63. package/src/io/export/twip.ts +1 -1
  64. package/src/io/normalize/normalize-text.ts +27 -20
  65. package/src/io/ooxml/chart/parse-series.ts +1 -1
  66. package/src/io/ooxml/chart/resolve-color.ts +2 -2
  67. package/src/io/ooxml/chart/types.ts +1 -1
  68. package/src/io/ooxml/classify-embedding.ts +83 -33
  69. package/src/io/ooxml/parse-fill.ts +1 -1
  70. package/src/io/ooxml/parse-main-document.ts +71 -1
  71. package/src/io/ooxml/parse-object.ts +14 -10
  72. package/src/io/ooxml/parse-run-formatting.ts +47 -1
  73. package/src/io/ooxml/property-grab-bag.ts +2 -2
  74. package/src/io/ooxml/units.ts +11 -0
  75. package/src/io/ooxml/workflow-payload.ts +282 -7
  76. package/src/model/anchor.ts +85 -0
  77. package/src/model/canonical-document.ts +351 -15
  78. package/src/model/chart-types.ts +1 -1
  79. package/src/model/layout/index.ts +83 -0
  80. package/src/model/layout/page-graph-types.ts +181 -0
  81. package/src/model/layout/page-layout-snapshot.ts +105 -0
  82. package/src/model/layout/resolved-layout-types.ts +47 -0
  83. package/src/model/layout/runtime-page-graph-types.ts +102 -0
  84. package/src/model/paragraph-scope-ids.ts +72 -0
  85. package/src/model/review/comment-types.ts +112 -0
  86. package/src/model/review/index.ts +2 -0
  87. package/src/model/review/revision-types.ts +215 -0
  88. package/src/model/snapshot.ts +32 -0
  89. package/src/review/store/comment-store.ts +21 -47
  90. package/src/review/store/revision-types.ts +40 -198
  91. package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
  92. package/src/runtime/collab/runtime-collab-sync.ts +13 -3
  93. package/src/runtime/collab-session.ts +1 -1
  94. package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
  95. package/src/runtime/debug/event-ring-buffer.ts +64 -0
  96. package/src/runtime/debug/probability-sampler.ts +18 -0
  97. package/src/runtime/debug/runtime-debug-facet.ts +67 -0
  98. package/src/runtime/debug/stage-tokens.ts +31 -0
  99. package/src/runtime/debug/telemetry-bus.ts +271 -0
  100. package/src/runtime/debug/types.ts +275 -0
  101. package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
  102. package/src/runtime/document-layout.ts +8 -6
  103. package/src/runtime/document-runtime.ts +843 -1141
  104. package/src/runtime/document-search.ts +1 -1
  105. package/src/runtime/edit-ops/index.ts +1 -1
  106. package/src/runtime/external-send-runtime.ts +1 -1
  107. package/src/runtime/formatting/document-lookup.ts +235 -0
  108. package/src/runtime/formatting/field/registry.ts +41 -0
  109. package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
  110. package/src/runtime/formatting/font-resolution.ts +83 -0
  111. package/src/runtime/formatting/formatting-context.ts +903 -0
  112. package/src/runtime/formatting/formatting-types.ts +157 -0
  113. package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
  114. package/src/runtime/formatting/index.ts +125 -0
  115. package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
  116. package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
  117. package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
  118. package/src/runtime/formatting/projector.ts +75 -0
  119. package/src/runtime/formatting/resolve-effective.ts +407 -0
  120. package/src/runtime/formatting/revision-display.ts +105 -0
  121. package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
  122. package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
  123. package/src/runtime/formatting/telemetry-bridge.ts +106 -0
  124. package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
  125. package/src/runtime/geometry/caret-geometry.ts +164 -0
  126. package/src/runtime/geometry/geometry-facet.ts +364 -0
  127. package/src/runtime/geometry/geometry-types.ts +256 -0
  128. package/src/runtime/geometry/hit-test.ts +125 -0
  129. package/src/runtime/geometry/index.ts +71 -0
  130. package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
  131. package/src/runtime/geometry/invalidation.ts +35 -0
  132. package/src/runtime/geometry/object-handles.ts +77 -0
  133. package/src/runtime/geometry/overlay-rects.ts +85 -0
  134. package/src/runtime/geometry/project-anchors.ts +100 -0
  135. package/src/runtime/geometry/project-fragments.ts +216 -0
  136. package/src/runtime/geometry/projector.ts +129 -0
  137. package/src/runtime/geometry/replacement-envelope.ts +130 -0
  138. package/src/runtime/geometry/viewport.ts +218 -0
  139. package/src/runtime/layout/compat-input-ledger.ts +211 -0
  140. package/src/runtime/layout/index.ts +6 -1
  141. package/src/runtime/layout/inert-layout-facet.ts +12 -7
  142. package/src/runtime/layout/layout-engine-instance.ts +189 -11
  143. package/src/runtime/layout/layout-engine-version.ts +450 -1
  144. package/src/runtime/layout/layout-facet-types.ts +60 -0
  145. package/src/runtime/layout/layout-measurement-provider.ts +13 -0
  146. package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
  147. package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
  148. package/src/runtime/layout/page-graph.ts +62 -209
  149. package/src/runtime/layout/page-story-resolver.ts +7 -12
  150. package/src/runtime/layout/paginated-layout-engine.ts +186 -11
  151. package/src/runtime/layout/project-block-fragments.ts +11 -0
  152. package/src/runtime/layout/projector.ts +90 -0
  153. package/src/runtime/layout/public-facet.ts +187 -442
  154. package/src/runtime/layout/resolved-formatting-state.ts +158 -26
  155. package/src/runtime/layout/table-render-plan.ts +1 -1
  156. package/src/runtime/prerender/cache-envelope.ts +6 -1
  157. package/src/runtime/prerender/prerender-document.ts +18 -23
  158. package/src/runtime/render/decoration-resolver.ts +1 -1
  159. package/src/runtime/render/render-frame-types.ts +20 -0
  160. package/src/runtime/render/render-kernel.ts +94 -25
  161. package/src/runtime/scopes/_formatting-seam.ts +262 -0
  162. package/src/runtime/scopes/_scope-dependencies.ts +49 -0
  163. package/src/runtime/scopes/action-validation.ts +356 -0
  164. package/src/runtime/scopes/attach-explanation.ts +102 -0
  165. package/src/runtime/scopes/audit-bundle.ts +71 -0
  166. package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
  167. package/src/runtime/scopes/compile-scope.ts +262 -0
  168. package/src/runtime/scopes/compiler-service.ts +431 -0
  169. package/src/runtime/scopes/create-issue.ts +107 -0
  170. package/src/runtime/scopes/enumerate-scopes.ts +543 -0
  171. package/src/runtime/scopes/evidence.ts +233 -0
  172. package/src/runtime/scopes/index.ts +150 -0
  173. package/src/runtime/scopes/position-map.ts +214 -0
  174. package/src/runtime/scopes/preservation-boundary.ts +91 -0
  175. package/src/runtime/scopes/projector.ts +49 -0
  176. package/src/runtime/scopes/replaceability.ts +87 -0
  177. package/src/runtime/scopes/replacement/apply.ts +228 -0
  178. package/src/runtime/scopes/replacement/compile.ts +59 -0
  179. package/src/runtime/scopes/replacement/propose.ts +42 -0
  180. package/src/runtime/scopes/resolve-reference.ts +347 -0
  181. package/src/runtime/scopes/review-bundle.ts +141 -0
  182. package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
  183. package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
  184. package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
  185. package/src/runtime/scopes/scope-kinds/field.ts +65 -0
  186. package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
  187. package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
  188. package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
  189. package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
  190. package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
  191. package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
  192. package/src/runtime/scopes/scope-kinds/table.ts +55 -0
  193. package/src/runtime/scopes/scope-range.ts +208 -0
  194. package/src/runtime/scopes/semantic-scope-types.ts +454 -0
  195. package/src/runtime/scopes/workflow-overlap.ts +92 -0
  196. package/src/runtime/selection/index.ts +1 -1
  197. package/src/runtime/structure-ops/fragment-insert.ts +1 -1
  198. package/src/runtime/structure-ops/index.ts +1 -1
  199. package/src/runtime/surface-projection.ts +232 -262
  200. package/src/runtime/units.ts +4 -2
  201. package/src/runtime/workflow/coordinator.ts +1348 -0
  202. package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
  203. package/src/runtime/workflow/index.ts +25 -0
  204. package/src/runtime/workflow/markup-mode-policy.ts +98 -0
  205. package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
  206. package/src/runtime/workflow/metadata-persistence.ts +306 -0
  207. package/src/runtime/workflow/metadata-writer.ts +123 -0
  208. package/src/runtime/workflow/overlay-store.ts +690 -0
  209. package/src/runtime/workflow/projector.ts +127 -0
  210. package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
  211. package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
  212. package/src/runtime/workflow/rail/types.ts +198 -0
  213. package/src/runtime/workflow/scope-rail-composer.ts +39 -0
  214. package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
  215. package/src/runtime/workflow/scope-writer.ts +188 -0
  216. package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
  217. package/src/runtime/workflow/visibility-policy.ts +129 -0
  218. package/src/session/_sync-legacy.ts +66 -0
  219. package/src/session/export/embedded-reconstitute.ts +104 -0
  220. package/src/session/export/export-diagnostics.ts +85 -0
  221. package/src/session/export/export-validation.ts +110 -0
  222. package/src/session/export/index.ts +34 -0
  223. package/src/session/export/preservation-reattach.ts +30 -0
  224. package/src/session/export/serialize-dispatch.ts +165 -0
  225. package/src/session/export/stateful-export-pipeline.ts +432 -0
  226. package/src/session/export/stateful-export.ts +684 -0
  227. package/src/session/import/canonical-assembly.ts +227 -0
  228. package/src/session/import/diagnostics-session.ts +54 -0
  229. package/src/session/import/embedded-discovery.ts +225 -0
  230. package/src/session/import/embedded-offload.ts +337 -0
  231. package/src/session/import/import-diagnostics.ts +69 -0
  232. package/src/session/import/loader-types.ts +313 -0
  233. package/src/session/import/loader.ts +1834 -0
  234. package/src/session/import/normalize.ts +195 -0
  235. package/src/session/import/package-parts.ts +217 -0
  236. package/src/session/import/package-read.ts +195 -0
  237. package/src/session/import/parse-orchestration.ts +105 -0
  238. package/src/session/import/part-constants.ts +70 -0
  239. package/src/session/import/part-discovery.ts +94 -0
  240. package/src/session/import/preservation-index.ts +46 -0
  241. package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
  242. package/src/session/import/review-import.ts +508 -0
  243. package/src/session/import/styles-consolidation.ts +281 -0
  244. package/src/session/import/workflow-scope-import.ts +256 -0
  245. package/src/session/index.ts +37 -0
  246. package/src/session/session-state.ts +69 -0
  247. package/src/session/session.ts +532 -0
  248. package/src/session/shared/protection.ts +228 -0
  249. package/src/session/shared/session-utils.ts +82 -0
  250. package/src/session/types.ts +499 -0
  251. package/src/shell/chart-snapshots.ts +96 -0
  252. package/src/shell/media-previews.ts +85 -0
  253. package/src/shell/overlay-anchor-bridge.ts +53 -0
  254. package/src/shell/paste-adapter.ts +23 -0
  255. package/src/shell/ref-commands.ts +1697 -0
  256. package/src/shell/ref-utilities.ts +48 -0
  257. package/src/shell/search.ts +51 -0
  258. package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
  259. package/src/shell/ui-subscriber-channels.ts +81 -0
  260. package/src/shell/use-collab-sync.ts +116 -0
  261. package/src/ui/WordReviewEditor.tsx +496 -2051
  262. package/src/ui/editor-shell-view.tsx +30 -1
  263. package/src/ui/editor-surface-controller.tsx +49 -1
  264. package/src/ui/headless/revision-decoration-model.ts +83 -0
  265. package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
  266. package/src/ui/headless/scoped-chrome-policy.ts +2 -2
  267. package/src/ui/headless/selection-tool-context.ts +1 -1
  268. package/src/ui/headless/selection-tool-resolver.ts +1 -1
  269. package/src/ui/runtime-shortcut-dispatch.ts +46 -1
  270. package/src/ui/ui-controller-factory.ts +221 -0
  271. package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
  272. package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
  273. package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
  274. package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
  275. package/src/ui-tailwind/chart/render/area.tsx +3 -3
  276. package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
  277. package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
  278. package/src/ui-tailwind/chart/render/combo.tsx +2 -2
  279. package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
  280. package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
  281. package/src/ui-tailwind/chart/render/line.tsx +3 -3
  282. package/src/ui-tailwind/chart/render/pie.tsx +6 -6
  283. package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
  284. package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
  285. package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
  286. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
  287. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
  288. package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
  289. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
  290. package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
  291. package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
  292. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
  293. package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
  294. package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
  295. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
  296. package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
  297. package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
  298. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
  299. package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
  300. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
  301. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
  302. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
  303. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
  304. package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
  305. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
  306. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
  307. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
  308. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
  309. package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
  310. package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
  311. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
  312. package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
  313. package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
  314. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
  315. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
  316. package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
  317. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
  318. package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
  319. package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
  320. package/src/ui-tailwind/debug/README.md +57 -0
  321. package/src/ui-tailwind/debug/index.ts +3 -0
  322. package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
  323. package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
  324. package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
  325. package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
  326. package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
  327. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
  328. package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
  329. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
  330. package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
  331. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
  332. package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
  333. package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
  334. package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
  335. package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
  336. package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
  337. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
  338. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
  339. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
  340. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
  341. package/src/ui-tailwind/index.ts +0 -5
  342. package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
  343. package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
  344. package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
  345. package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
  346. package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
  347. package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
  348. package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
  349. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
  350. package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
  351. package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
  352. package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
  353. package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
  354. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
  355. package/src/ui-tailwind/review-workspace/types.ts +408 -0
  356. package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
  357. package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
  358. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
  359. package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
  360. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
  361. package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
  362. package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
  363. package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
  364. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
  365. package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
  366. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
  367. package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
  368. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
  369. package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
  370. package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
  371. package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
  372. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
  373. package/src/ui-tailwind/theme/editor-theme.css +25 -0
  374. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
  375. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
  376. package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
  377. package/src/ui-tailwind/ui-api-context.tsx +43 -0
  378. package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
  379. package/src/validation/compatibility-engine.ts +6 -6
  380. package/src/runtime/styles-cascade.ts +0 -33
  381. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
  382. /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
  383. /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
  384. /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shell re-export module — the seam that hosts substrate-reach-through
3
+ * helpers `WordReviewEditor` still consumes after the Track A
4
+ * ref-bridge carve-out. Layer 11 presentation code (`src/ui/**` +
5
+ * `src/ui-tailwind/**`) imports from this module instead of reaching
6
+ * directly into `src/core/**` or `src/runtime/**`, which retires
7
+ * those imports from the L11 boundary register.
8
+ *
9
+ * The shell layer is an allowed substrate consumer (handoff §3,
10
+ * designsystem.md §8.8 "Mounted shell" stratum); presentation
11
+ * reads through it.
12
+ *
13
+ * Each binding below is a straight re-export — no runtime wrapping,
14
+ * no behavioral change, no perf cost. Hot-path consumers
15
+ * (`dispatchTextCommand` called on every keystroke) retain identity
16
+ * stability; the ESM re-export binding is folded at module load.
17
+ *
18
+ * Track D + G · refactor/11 — closes the WRE-side substrate leakage
19
+ * that Track A (ref-bridge carve-out) did not touch. After this
20
+ * module ships, `WordReviewEditor.tsx` still holds ~2 direct
21
+ * substrate imports for trivial type-only use that routes cleanly
22
+ * through `src/api/public-types.ts`; the rest travel through here.
23
+ */
24
+
25
+ export { storyTargetsEqual } from "../core/selection/mapping.ts";
26
+ export { getFormattingStateFromRenderSnapshot } from "../core/commands/formatting-commands.ts";
27
+ export {
28
+ dispatchTextCommand,
29
+ type DispatchTextCommand,
30
+ } from "../runtime/edit-dispatch/index.ts";
31
+ export { getTableStructureContext } from "../core/commands/table-structure-commands.ts";
32
+ export { getStoryBlocks } from "../runtime/story-targeting.ts";
33
+ export { deriveCapabilities } from "../runtime/session-capabilities";
34
+ export {
35
+ resolveCurrentContextAnalyticsQuery,
36
+ runtimeContextAnalyticsSnapshotsEqual,
37
+ } from "../runtime/context-analytics.ts";
38
+ export {
39
+ createEditorViewStateSnapshot,
40
+ createViewState,
41
+ } from "../runtime/view-state.ts";
42
+ export { wrapRefForTelemetry } from "../runtime/debug/wrap-ref-for-telemetry.ts";
43
+ export {
44
+ conflictKey,
45
+ convertScopesToInternal,
46
+ convertScopesToExternal,
47
+ type PendingConflict,
48
+ } from "../runtime/workflow/metadata-persistence.ts";
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Shell helper — document search projections.
3
+ *
4
+ * Two thin projections used by the React editor ref (`findText`,
5
+ * `searchDocument`) plus the in-component search effects. Both take
6
+ * the mounted runtime and return public-API shapes.
7
+ *
8
+ * Lives in `src/shell/` rather than `src/ui/` so the underlying
9
+ * `src/runtime/document-search.ts` value import is a consumer
10
+ * relationship rather than an L11 register offender.
11
+ */
12
+
13
+ import type { EditorAnchorProjection, SearchOptions, SearchResultSnapshot } from "../api/public-types.ts";
14
+ import { findTextMatches, searchDocument } from "../runtime/document-search.ts";
15
+ import type { WordReviewEditorRuntime } from "./session-bootstrap.ts";
16
+ import type { TwProseMirrorSurfaceRef } from "../ui-tailwind/editor-surface/tw-prosemirror-surface";
17
+
18
+ export function findTextMatchesForRuntime(
19
+ runtime: WordReviewEditorRuntime,
20
+ query: string,
21
+ options: SearchOptions | undefined,
22
+ ): EditorAnchorProjection[] {
23
+ const snapshot = runtime.getRenderSnapshot();
24
+ return findTextMatches(
25
+ runtime.getSessionState().canonicalDocument,
26
+ snapshot.selection,
27
+ query,
28
+ options ?? {},
29
+ );
30
+ }
31
+
32
+ export function searchRuntimeDocument(
33
+ runtime: WordReviewEditorRuntime,
34
+ mountedSurface: TwProseMirrorSurfaceRef | null,
35
+ query: string,
36
+ options: SearchOptions = {},
37
+ ): SearchResultSnapshot[] {
38
+ if (mountedSurface) {
39
+ return mountedSurface.search(query, options);
40
+ }
41
+
42
+ const snapshot = runtime.getRenderSnapshot();
43
+ return searchDocument(
44
+ runtime.getSessionState().canonicalDocument,
45
+ snapshot.selection,
46
+ snapshot.activeStory,
47
+ runtime.getDocumentNavigationSnapshot(),
48
+ query,
49
+ options,
50
+ );
51
+ }
@@ -29,7 +29,11 @@ import {
29
29
  editorSessionStateFromPersistedSnapshot,
30
30
  persistedSnapshotFromEditorSessionState,
31
31
  } from "../api/session-state.ts";
32
- import { createCanonicalDocumentId } from "../core/state/editor-state.ts";
32
+ import {
33
+ createCanonicalDocumentId,
34
+ createDefaultCanonicalDocument,
35
+ createSelectionSnapshot,
36
+ } from "../core/state/editor-state.ts";
33
37
  import {
34
38
  createDocumentRuntime,
35
39
  type DocumentRuntimeEvent,
@@ -41,15 +45,31 @@ import {
41
45
  type RuntimeCommandAppliedBridge,
42
46
  } from "../runtime/collab/runtime-collab-sync.ts";
43
47
  import { createInertLayoutFacet } from "../runtime/layout/index.ts";
48
+ import { createInertGeometryFacet } from "../runtime/geometry/index.ts";
49
+ import { TelemetryBus } from "../runtime/debug/telemetry-bus.ts";
44
50
  import {
45
- loadDocxEditorSession,
46
- loadDocxEditorSessionAsync,
47
- } from "../io/docx-session.ts";
51
+ createRuntimeDebugFacet,
52
+ type RuntimeDebugFacet,
53
+ } from "../runtime/debug/runtime-debug-facet.ts";
54
+ // Slice 5c flipped the async DOM warm path to `DocxSession.open()`.
55
+ // The two remaining sync call sites (SSR/Node `createRuntime`
56
+ // fallback + `resolvePackageBackedExportSession`) were isolated
57
+ // behind `src/session/_sync-legacy.ts` in Slice 5e-3 so the UI layer
58
+ // no longer imports directly from the legacy file. The shim + its
59
+ // debt exception in `ci-check-session-layer-purity.mjs` go away at
60
+ // Slice 5e-9 together with the legacy file.
61
+ import type { CacheEnvelope } from "../runtime/prerender/cache-envelope.ts";
48
62
  import { tryReadLaycacheEnvelope } from "../runtime/prerender/customxml-probe.ts";
49
- import {
50
- createLoadScheduler,
51
- type LoadScheduler,
52
- } from "../io/load-scheduler.ts";
63
+ import { createEditorSurfaceSnapshot } from "../runtime/surface-projection.ts";
64
+ import { MAIN_STORY_TARGET } from "../core/selection/mapping.ts";
65
+ import type { ProgressiveSurfaceProjector } from "../session/types.ts";
66
+ import { DocxSession } from "../session/index.ts";
67
+ // Slice 5e-11 item-4: `_internal-legacy.ts` retired. All fields that
68
+ // were reached through `getLegacyOpenView` are now public on
69
+ // `OpenResult` directly; a tiny local adapter maps `OpenResult` into
70
+ // the `LoadedDocxEditorSession` shape the downstream shell code
71
+ // still expects.
72
+ import { openDocxSync } from "../session/_sync-legacy.ts";
53
73
  import {
54
74
  decodePersistedSourcePackageBytes,
55
75
  hasValidPersistedSourcePackageDigest,
@@ -65,7 +85,7 @@ import {
65
85
  import {
66
86
  downloadExportResult,
67
87
  withExportDelivery,
68
- } from "./browser-export";
88
+ } from "../ui/browser-export";
69
89
 
70
90
  export interface ResolvedSource {
71
91
  source: "docx" | "session" | "snapshot";
@@ -80,7 +100,7 @@ export interface ResolvedSource {
80
100
  * load. Undefined in SSR / Node test fallback — `createRuntime` then
81
101
  * does the classic synchronous load.
82
102
  */
83
- preloadedDocxSession?: ReturnType<typeof loadDocxEditorSession>;
103
+ preloadedDocxSession?: ReturnType<typeof openDocxSync>;
84
104
  /**
85
105
  * L7 Phase 2.7 — when the editor-runtime-boundary probe finds a
86
106
  * laycache envelope in `/customXml/item1.xml`, its `graph` is stashed
@@ -128,7 +148,7 @@ type InternalWordReviewEditorRuntime = WordReviewEditorRuntime & {
128
148
  ) => boolean;
129
149
  };
130
150
 
131
- type PackageBackedDocxSession = ReturnType<typeof loadDocxEditorSession>;
151
+ type PackageBackedDocxSession = ReturnType<typeof openDocxSync>;
132
152
 
133
153
  interface SnapshotExportBarrier {
134
154
  reason:
@@ -324,9 +344,11 @@ export function useEditorRuntimeBoundary(
324
344
  useRef<EditorSessionState["canonicalDocument"] | null>(null);
325
345
  const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
326
346
  const lastSavedRevisionTokenRef = useRef<string | null>(null);
327
- // Fastload P6: scheduler used by the DOM-side async docx loader. Held
328
- // here so it can be disposed on unmount / source change.
329
- const loadSchedulerRef = useRef<LoadScheduler | null>(null);
347
+ // Fastload P6: load-scheduler disposer handed back from
348
+ // `DocxSession.open()` via `LegacyOpenView.dispose`. Held here so
349
+ // unmount / source-change can cancel pending idle chart-preview
350
+ // callbacks (CLAUDE.md Performance Invariant 9).
351
+ const loadDisposeRef = useRef<(() => void) | null>(null);
330
352
  const hostAdapterRef = useRef(hostAdapter);
331
353
  const datastoreRef = useRef(datastore);
332
354
  const onEventRef = useRef(onEvent);
@@ -407,8 +429,8 @@ export function useEditorRuntimeBoundary(
407
429
  runtimeRef.current = null;
408
430
  // Fastload P6: dispose any scheduler held from a previous mount /
409
431
  // source cycle before allocating a fresh one for this load.
410
- loadSchedulerRef.current?.dispose();
411
- loadSchedulerRef.current = null;
432
+ loadDisposeRef.current?.();
433
+ loadDisposeRef.current = null;
412
434
  setRuntime(null);
413
435
 
414
436
  try {
@@ -429,37 +451,28 @@ export function useEditorRuntimeBoundary(
429
451
  return;
430
452
  }
431
453
 
432
- // Fastload P6: in a DOM environment, preload the docx via the
433
- // async loader so normalize-body yields mid-walk and the browser
434
- // can paint the skeleton while the rest of the parse finishes.
435
- // SSR / Node tests fall through to the synchronous load inside
436
- // `createRuntime`.
454
+ // Fastload P6: in a DOM environment, preload the docx via
455
+ // `DocxSession.open()` so normalize-body yields mid-walk and the
456
+ // browser can paint the skeleton while the rest of the parse
457
+ // finishes. SSR / Node tests fall through to the synchronous
458
+ // load inside `createRuntime`.
437
459
  //
438
- // L7 Phase 2.7 — Plan B read-path wiring. Before invoking the
439
- // async loader, probe the docx for a laycache envelope stashed
440
- // in `/customXml/item1.xml` (shipped by Plan B Slice 2). When the
441
- // probe returns a validated envelope, pass it to the loader so
442
- // the five expensive parse stages short-circuit against the
443
- // cached `canonicalDocument`. Measured win on 138-pp extra-large
444
- // CCEP: ~947 ms cold → ~590 ms warm (Δ 376 ms), same delta the
445
- // Node-side `prerender-cache.bench.ts` records. Probe is ~20–50 ms;
446
- // `tryReadLaycacheEnvelope` returns null on any rejection path
447
- // (missing part, stale structural hash, schema mismatch) and the
448
- // loader falls through to the full parse.
460
+ // L7 Phase 2.7 — Plan B read-path wiring. `tryLaycacheEnvelope:
461
+ // true` tells the session to probe `/customXml/item1.xml` for a
462
+ // cached envelope and short-circuit the five expensive parse
463
+ // stages on a hit (CLAUDE.md Performance Invariant 10 probe
464
+ // and loader are now colocated inside the session; no blocking
465
+ // work between them). Measured win on 138-pp extra-large CCEP:
466
+ // ~947 ms cold → ~590 ms warm (Δ 376 ms).
467
+ //
468
+ // `onProgressiveSnapshot` is passed unconditionally the
469
+ // loader gates it on `laycacheEnvelope === undefined`, so the
470
+ // warm-path short-circuit skips the synthesis automatically.
449
471
  if (
450
472
  source.initialDocx !== undefined &&
451
473
  source.preloadedDocxSession === undefined &&
452
474
  typeof document !== "undefined"
453
475
  ) {
454
- const scheduler = createLoadScheduler();
455
- loadSchedulerRef.current = scheduler;
456
- const probeResult = await tryReadLaycacheEnvelope(source.initialDocx);
457
- if (cancelled) {
458
- scheduler.dispose();
459
- loadSchedulerRef.current = null;
460
- return;
461
- }
462
- recordPerfSample("loadSession.laycacheProbe");
463
476
  const handleChartPreviewsReady = (
464
477
  resolvedDocument: EditorSessionState["canonicalDocument"],
465
478
  ): void => {
@@ -481,34 +494,89 @@ export function useEditorRuntimeBoundary(
481
494
  runtimeRef.current as InternalWordReviewEditorRuntime | null
482
495
  )?.hydrateChartPreviews?.(resolvedDocument);
483
496
  };
484
- const preloaded = await loadDocxEditorSessionAsync({
497
+ // Slice 5e-7.b runtime-side port that lets the session
498
+ // layer synthesize the progressive surface without importing
499
+ // `src/runtime/surface-projection.ts` directly. The adapter
500
+ // binds in a default collapsed selection + `MAIN_STORY_TARGET`
501
+ // + a provisional canonical envelope so the session only
502
+ // passes the body-stage root content + viewport counts.
503
+ const surfaceProjector: ProgressiveSurfaceProjector = ({
504
+ rootContent,
505
+ documentId: providedDocumentId,
506
+ blocksRealized,
507
+ blocksTotal,
508
+ }) => {
509
+ const provisionalDoc = {
510
+ ...createDefaultCanonicalDocument(
511
+ providedDocumentId,
512
+ new Date().toISOString(),
513
+ ),
514
+ content: rootContent,
515
+ };
516
+ return createEditorSurfaceSnapshot(
517
+ provisionalDoc,
518
+ createSelectionSnapshot(0, 0),
519
+ MAIN_STORY_TARGET,
520
+ blocksRealized < blocksTotal
521
+ ? { viewportBlockRange: { start: 0, end: blocksRealized } }
522
+ : undefined,
523
+ );
524
+ };
525
+ const openResult = await new DocxSession().open(source.initialDocx, {
485
526
  documentId,
486
527
  sourceLabel: source.sourceLabel,
487
- bytes: source.initialDocx,
488
528
  editorBuild: "dev",
489
- scheduler,
529
+ tryLaycacheEnvelope: true,
530
+ // Slice 5e-11 item-1: probe injection. Session no longer
531
+ // imports from `src/runtime/prerender/**`; the shell
532
+ // supplies the probe. See `cross-layer-coord-01 §1`.
533
+ laycacheProbe: tryReadLaycacheEnvelope,
490
534
  onChartPreviewsReady: handleChartPreviewsReady,
491
- ...(probeResult ? { laycacheEnvelope: probeResult.envelope } : {
492
- // C2c: on the cold path (no cached envelope), emit the first
493
- // viewport surface as soon as body-normalize completes so the
494
- // UI can show the first page before the full session is ready.
495
- // Wrapped in startTransition so React treats this as a
496
- // low-priority update the full setRuntime commit (urgent)
497
- // will preempt it if it arrives before React flushes the
498
- // transition.
499
- onProgressiveSnapshot: (partial) => {
500
- React.startTransition(() => {
501
- setProgressiveSurface(partial.surface);
502
- });
503
- },
504
- }),
535
+ surfaceProjector,
536
+ // C2c: on the cold path the loader fires this once after
537
+ // body-normalize with a viewport-windowed surface; on the
538
+ // warm path (envelope resolved) it is silently skipped.
539
+ // Performance Invariant 8: MUST be wrapped in
540
+ // `startTransition` so React treats it as low-priority;
541
+ // the full `setRuntime` commit preempts it.
542
+ onProgressiveSnapshot: (partial) => {
543
+ React.startTransition(() => {
544
+ setProgressiveSurface(partial.surface ?? null);
545
+ });
546
+ },
505
547
  });
548
+ // Slice 5e-11 item-4: adapter maps `OpenResult` → the
549
+ // `LoadedDocxEditorSession` shape the downstream shell
550
+ // code expects. Two field-name mismatches exist:
551
+ // `sessionState` / `initialSessionState`, and
552
+ // `embeddedDocuments` / `embeddedDocumentManifests`.
553
+ const preloadView: ReturnType<typeof openDocxSync> = {
554
+ initialSessionState: openResult.sessionState,
555
+ initialSnapshot: openResult.initialSnapshot,
556
+ readOnly: openResult.readOnly,
557
+ ...(openResult.fatalError !== undefined
558
+ ? { fatalError: openResult.fatalError }
559
+ : {}),
560
+ protectionSnapshot: openResult.protectionSnapshot,
561
+ exportDocx: openResult.exportDocx,
562
+ embeddedDocumentManifests: openResult.embeddedDocuments,
563
+ ...(openResult.initialEditorStatePayload !== undefined
564
+ ? {
565
+ initialEditorStatePayload:
566
+ openResult.initialEditorStatePayload as NonNullable<
567
+ ReturnType<typeof openDocxSync>["initialEditorStatePayload"]
568
+ >,
569
+ }
570
+ : {}),
571
+ };
572
+ loadDisposeRef.current = openResult.dispose ?? null;
506
573
  if (cancelled) {
507
- scheduler.dispose();
508
- loadSchedulerRef.current = null;
574
+ openResult.dispose?.();
575
+ loadDisposeRef.current = null;
509
576
  return;
510
577
  }
511
- source.preloadedDocxSession = preloaded;
578
+ recordPerfSample("loadSession.laycacheProbe");
579
+ source.preloadedDocxSession = preloadView;
512
580
  if (pendingChartPreviewDocRef.current) {
513
581
  source.preloadedDocxSession.initialSessionState = {
514
582
  ...source.preloadedDocxSession.initialSessionState,
@@ -519,8 +587,10 @@ export function useEditorRuntimeBoundary(
519
587
  canonicalDocument: pendingChartPreviewDocRef.current,
520
588
  };
521
589
  }
522
- if (probeResult) {
523
- source.preloadedLaycacheGraph = probeResult.envelope.graph;
590
+ if (openResult.laycacheEnvelope) {
591
+ source.preloadedLaycacheGraph = (
592
+ openResult.laycacheEnvelope as CacheEnvelope
593
+ ).graph;
524
594
  }
525
595
  }
526
596
 
@@ -643,8 +713,8 @@ export function useEditorRuntimeBoundary(
643
713
  // Fastload P6: release any pending idle callbacks the load scheduler
644
714
  // registered so React unmount doesn't leak setTimeout/IdleCallback
645
715
  // handles.
646
- loadSchedulerRef.current?.dispose();
647
- loadSchedulerRef.current = null;
716
+ loadDisposeRef.current?.();
717
+ loadDisposeRef.current = null;
648
718
  };
649
719
  }, []);
650
720
 
@@ -740,7 +810,7 @@ function createRuntime(
740
810
  const docxSession =
741
811
  args.source.preloadedDocxSession ??
742
812
  (args.source.initialDocx
743
- ? loadDocxEditorSession({
813
+ ? openDocxSync({
744
814
  documentId: args.documentId,
745
815
  sourceLabel: args.source.sourceLabel,
746
816
  bytes: args.source.initialDocx,
@@ -985,6 +1055,7 @@ function createLoadingRuntimeBridge(input: {
985
1055
  progressiveSurfaceRef?: React.RefObject<EditorSurfaceSnapshot | null>;
986
1056
  }): WordReviewEditorRuntime {
987
1057
  const inertLayoutFacet = createInertLayoutFacet();
1058
+ const inertGeometryFacet = createInertGeometryFacet();
988
1059
  const emptyFieldSnapshot: FieldSnapshot = {
989
1060
  totalCount: 0,
990
1061
  supportedCount: 0,
@@ -1027,6 +1098,7 @@ function createLoadingRuntimeBridge(input: {
1027
1098
  getFontEntry: (name: string) =>
1028
1099
  input.sessionState.canonicalDocument.fontTable?.fonts[name],
1029
1100
  replaceText: () => undefined,
1101
+ applyScopeReplacement: () => undefined,
1030
1102
  insertFragment: () => undefined,
1031
1103
  copy: () => undefined,
1032
1104
  cut: () => undefined,
@@ -1066,6 +1138,9 @@ function createLoadingRuntimeBridge(input: {
1066
1138
  throw createLoadingBoundaryError(input.snapshot.documentId, "scope");
1067
1139
  },
1068
1140
  getScope: () => null,
1141
+ compileScopeBundleById: () => null,
1142
+ getMarkerBackedScopeIds: () => new Set<string>(),
1143
+ debug: createLoadingDebugFacet(),
1069
1144
  removeScope: () => undefined,
1070
1145
  acceptChange: () => undefined,
1071
1146
  rejectChange: () => undefined,
@@ -1086,6 +1161,13 @@ function createLoadingRuntimeBridge(input: {
1086
1161
  getPageLayoutSnapshot: () => null,
1087
1162
  getDocumentNavigationSnapshot: () => input.navigation,
1088
1163
  layout: inertLayoutFacet,
1164
+ workflow: {
1165
+ getRailSegments: () => [],
1166
+ getAllRailSegments: () => [],
1167
+ getAllScopeCardModels: () => [],
1168
+ },
1169
+ geometry: inertGeometryFacet,
1170
+ getLayoutFacet: () => inertLayoutFacet,
1089
1171
  getCurrentLocation: () => null,
1090
1172
  getLocationForSelection: () => null,
1091
1173
  getLocationForAnchor: () => null,
@@ -1156,6 +1238,18 @@ function createLoadingRuntimeBridge(input: {
1156
1238
  definitions: [],
1157
1239
  entries: [],
1158
1240
  }),
1241
+ // W10 — class-A overlay-visibility policy. Loading bridge: no
1242
+ // authored policy until the real runtime mounts.
1243
+ getVisibilityPolicy: () => null,
1244
+ getVisibilityPolicies: () => [],
1245
+ setVisibilityPolicy: () => false,
1246
+ clearVisibilityPolicy: () => false,
1247
+ subscribeVisibilityPolicy: () => () => undefined,
1248
+ getMarkupModePolicy: () => null,
1249
+ setMarkupModePolicy: () => false,
1250
+ subscribeMarkupModePolicy: () => () => undefined,
1251
+ setEffectiveMarkupModeProvider: () => undefined,
1252
+ invalidateForMarkupModeChange: () => undefined,
1159
1253
  queryScopes: () => [],
1160
1254
  findScopesAt: () => [],
1161
1255
  findScopesIntersecting: () => [],
@@ -1200,6 +1294,88 @@ function createLoadingRuntimeBridge(input: {
1200
1294
  };
1201
1295
  }
1202
1296
 
1297
+ /**
1298
+ * Loading-bridge debug facet. Exposes an all-off `TelemetryBus` and a
1299
+ * projector that only renders the current loading state. Consumers that
1300
+ * connect the debug facet before the runtime is live (e.g. the Phase 2
1301
+ * service during cold-open) see an honest empty bundle, not an error.
1302
+ */
1303
+ function createLoadingDebugFacet(): RuntimeDebugFacet {
1304
+ const bus = new TelemetryBus();
1305
+ return {
1306
+ bus,
1307
+ getSnapshot() {
1308
+ return {
1309
+ schemaVersion: 1,
1310
+ generatedAtUtc: new Date().toISOString(),
1311
+ session: {
1312
+ documentId: "",
1313
+ sessionId: "",
1314
+ dirty: false,
1315
+ exportBlocked: true,
1316
+ activeStory: { kind: "main" },
1317
+ workspaceMode: "canvas",
1318
+ viewMode: "loading",
1319
+ documentMode: "loading",
1320
+ measurementFidelity: null,
1321
+ currentPage: null,
1322
+ },
1323
+ health: {
1324
+ compatibility: {
1325
+ exportAllowed: false,
1326
+ exportPlan: "full",
1327
+ featureBlocked: false,
1328
+ warnings: [],
1329
+ features: [],
1330
+ summary: { blockedCount: 0, preserveOnlyCount: 0, warningCount: 0 },
1331
+ generatedAt: new Date().toISOString(),
1332
+ blockedFeatureKeys: [],
1333
+ preserveOnlyFeatureKeys: [],
1334
+ } as never,
1335
+ warnings: [],
1336
+ blockedReasons: [],
1337
+ fatalError: null,
1338
+ readOnly: false,
1339
+ },
1340
+ context: null,
1341
+ selection: { anchor: null, location: null },
1342
+ workflow: {
1343
+ overlay: null,
1344
+ activeWorkItemId: null,
1345
+ metadataPersistenceMode: null,
1346
+ candidateCount: 0,
1347
+ scopeCount: 0,
1348
+ markerBackedCount: 0,
1349
+ overlayOnlyCount: 0,
1350
+ detachedCount: 0,
1351
+ },
1352
+ scopes: [],
1353
+ review: {
1354
+ unresolvedCommentCount: 0,
1355
+ pendingRevisionCount: 0,
1356
+ detachedCommentCount: 0,
1357
+ detachedRevisionCount: 0,
1358
+ },
1359
+ layout: { pageCount: null, sectionCount: null, storyCount: 0 },
1360
+ channels: bus.getChannels(),
1361
+ };
1362
+ },
1363
+ tail(n = 64) {
1364
+ return bus.tailAll(n);
1365
+ },
1366
+ tailChannel(channel, n = 64) {
1367
+ return bus.tail(channel, n);
1368
+ },
1369
+ setChannels(flags) {
1370
+ bus.setChannels(flags);
1371
+ return bus.getChannels();
1372
+ },
1373
+ getChannels() {
1374
+ return bus.getChannels();
1375
+ },
1376
+ };
1377
+ }
1378
+
1203
1379
  function createLoadingBoundaryError(
1204
1380
  documentId: string,
1205
1381
  target: "comment" | "session" | "snapshot" | "export" | "scope",
@@ -1717,7 +1893,7 @@ function resolvePackageBackedExportSession(args: CreateRuntimeArgs): {
1717
1893
  };
1718
1894
  }
1719
1895
 
1720
- const session = loadDocxEditorSession({
1896
+ const session = openDocxSync({
1721
1897
  documentId: args.documentId,
1722
1898
  sourceLabel: sourcePackage.sourceLabel ?? args.source.sourceLabel,
1723
1899
  bytes,
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Shell-side subscriber-emitter channels for the mounted UI API
3
+ * controller hooks (`subscribeChrome`, `subscribeViewport`,
4
+ * `subscribeOverlays`).
5
+ *
6
+ * Why this exists
7
+ *
8
+ * `ui.chrome.subscribe` / `ui.viewport.subscribe` / `ui.overlays.subscribe`
9
+ * delegate to their respective controller hooks. Until 2026-04-23 those
10
+ * hooks were `undefined` on the mounted path, causing each subscribe to
11
+ * throw with a configuration-clear error. That's fine for consumer
12
+ * discovery but it means Playwright drivers, the debug service, and any
13
+ * non-React consumer that wants to observe posture / viewport /
14
+ * overlay-invalidation over time couldn't actually do it on the mounted
15
+ * editor.
16
+ *
17
+ * The three channels here are **stable per-mount** emitter triples:
18
+ *
19
+ * - `subscribe(listener) → unsubscribe`
20
+ * - `emit(value)` — called by the shell at event time
21
+ * - `size` — count of current listeners (test + telemetry hook)
22
+ *
23
+ * The shell creates one of each via `useRef` at mount, wires `subscribeX`
24
+ * on the UI controller factory to the emitter's `subscribe`, and calls
25
+ * `.emit(value)` from the appropriate React effect / DOM listener when
26
+ * the underlying state changes. The factory's controller identity stays
27
+ * stable because the emitter object identity is stable (a ref box).
28
+ *
29
+ * U7 compliance: viewport and overlay emitters are **rAF-coalesced at
30
+ * the shell-call-site level**, not inside the emitter. The emitter is a
31
+ * dumb fan-out; coalescing is the responsibility of whatever is calling
32
+ * `.emit()`. Posture is microtask-coalesced because the posture sources
33
+ * are synchronous React state / props and batching is React's default.
34
+ *
35
+ * Isolation: each emitter holds its own listener set. Teardown at
36
+ * unmount clears the set so a stale listener can't leak across remounts.
37
+ */
38
+
39
+ export interface UiSubscriberChannel<T> {
40
+ /** Register a listener; returns an unsubscribe fn. Idempotent add. */
41
+ readonly subscribe: (listener: (value: T) => void) => () => void;
42
+ /** Fire every registered listener with `value`. Errors isolated. */
43
+ readonly emit: (value: T) => void;
44
+ /** Clear the listener set (call on unmount). Subsequent emits no-op. */
45
+ readonly dispose: () => void;
46
+ /** Current listener count (test / telemetry). */
47
+ readonly size: () => number;
48
+ }
49
+
50
+ /**
51
+ * Build a stable emitter channel. Listeners are held in a Set so
52
+ * registration is idempotent (adding the same fn twice leaves one
53
+ * entry). Removal is O(1). Emission isolates listener throws so one
54
+ * broken consumer can't break the fan-out.
55
+ */
56
+ export function createUiSubscriberChannel<T>(): UiSubscriberChannel<T> {
57
+ const listeners = new Set<(value: T) => void>();
58
+ return {
59
+ subscribe(listener) {
60
+ listeners.add(listener);
61
+ return () => {
62
+ listeners.delete(listener);
63
+ };
64
+ },
65
+ emit(value) {
66
+ for (const listener of listeners) {
67
+ try {
68
+ listener(value);
69
+ } catch {
70
+ // One broken listener must not break the fan-out.
71
+ }
72
+ }
73
+ },
74
+ dispose() {
75
+ listeners.clear();
76
+ },
77
+ size() {
78
+ return listeners.size;
79
+ },
80
+ };
81
+ }