@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,499 @@
1
+ /**
2
+ * Layer 01 public type surface for `src/session/**`.
3
+ *
4
+ * These types mirror the reserved shape in
5
+ * `docs/architecture/01-package-session.md` § "Public entry points".
6
+ * They are the contract consumers see; the implementation in
7
+ * `src/session/session.ts` may still delegate transitionally to the
8
+ * legacy `src/io/docx-session.ts` while the extraction completes.
9
+ *
10
+ * P6 clean: imports only from `src/api/**` (type-only), `src/model/**`,
11
+ * `src/io/**`, and `src/preservation/**`.
12
+ */
13
+
14
+ import type {
15
+ CanonicalDocument,
16
+ DocumentRootNode,
17
+ } from "../model/canonical-document.ts";
18
+ import type {
19
+ CompatibilityReport,
20
+ EditorError,
21
+ EditorHostAdapter,
22
+ EditorSurfaceSnapshot,
23
+ ExportDocxOptions,
24
+ ExportResult,
25
+ LoadStage,
26
+ PersistedEditorSnapshot,
27
+ ProtectionSnapshot,
28
+ } from "../api/public-types.ts";
29
+ import type { EmbeddingKind } from "../io/ooxml/classify-embedding.ts";
30
+ import type { LoadSchedulerBackend } from "../io/load-scheduler.ts";
31
+ import type { PreservationStore } from "../model/canonical-document.ts";
32
+ import type { EditorSessionState } from "./session-state.ts";
33
+
34
+ // Re-export legacy types so downstream consumers that still need them
35
+ // during the transition can reach them from the session barrel. These
36
+ // are explicitly transitional and scheduled for removal in Slice 5 once
37
+ // the legacy `src/io/docx-session.ts` is deleted.
38
+ export type {
39
+ EditorHostAdapter,
40
+ ExportDocxOptions,
41
+ ExportResult,
42
+ LoadStage,
43
+ PersistedEditorSnapshot,
44
+ };
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Runtime-side projection ports
48
+ // ---------------------------------------------------------------------------
49
+
50
+ /**
51
+ * Input passed by the session load path to a caller-supplied
52
+ * `ProgressiveSurfaceProjector`. The session carries the body-stage
53
+ * normalized root content plus the viewport accounting it has already
54
+ * computed; the projector assembles a provisional canonical envelope
55
+ * and calls the runtime-layer `createEditorSurfaceSnapshot` with a
56
+ * default selection + `MAIN_STORY_TARGET`.
57
+ *
58
+ * Kept deliberately minimal — extending the contract requires a
59
+ * coordinated change in the session load path + every consumer.
60
+ */
61
+ export interface ProgressiveSurfaceProjectorInput {
62
+ /** Body-stage normalized root content. */
63
+ rootContent: DocumentRootNode;
64
+ /** Document id stamped on the provisional canonical envelope. */
65
+ documentId: string;
66
+ /** First-paint viewport size (blocks in the windowed view). */
67
+ blocksRealized: number;
68
+ /** Total block count in the normalized document. */
69
+ blocksTotal: number;
70
+ }
71
+
72
+ /**
73
+ * Runtime-side port invoked by the session to synthesize the
74
+ * progressive surface without pulling `src/runtime/**` into the session
75
+ * layer. The UI boundary implements it by binding in
76
+ * `createEditorSurfaceSnapshot` + a default selection + the main story
77
+ * target; tests bind the same runtime helper directly.
78
+ */
79
+ export type ProgressiveSurfaceProjector = (
80
+ input: ProgressiveSurfaceProjectorInput,
81
+ ) => EditorSurfaceSnapshot;
82
+
83
+ // ---------------------------------------------------------------------------
84
+ // Reserved Layer-01 options + results (architecture §Public entry points)
85
+ // ---------------------------------------------------------------------------
86
+
87
+ /**
88
+ * Options for `DocxSession.open(bytes, opts)`.
89
+ *
90
+ * Field list mirrors the legacy `LoadDocxEditorSessionOptions` minus
91
+ * `bytes` (now a positional arg) and minus options that are specific to
92
+ * the internal async scheduler (the session class handles scheduler
93
+ * selection itself). Hosts pass their adapter and optional telemetry
94
+ * bus; everything else is wired from the session internals.
95
+ */
96
+ export interface OpenOptions {
97
+ /**
98
+ * Stable document identifier minted by the host. Flows through to
99
+ * `EditorSessionState.documentId` + `OpenResult.sessionState`.
100
+ */
101
+ documentId?: string;
102
+ /** Human-readable label, surfaced in telemetry only. */
103
+ sourceLabel?: string;
104
+ /** Optional editor build identifier; default is the package version. */
105
+ editorBuild?: string;
106
+ /** Host adapter for chart previews, session storage, logging. */
107
+ hostAdapter?: EditorHostAdapter;
108
+ /**
109
+ * P8 Step 7 — explicit opt-in for embedded-document offload at
110
+ * load time. When `true` AND `hostAdapter.storeEmbeddedDocument`
111
+ * is defined, the session materialises every `offloadable`
112
+ * embedded document, computes sha-256, calls the adapter, and
113
+ * persists the `bw:embeddings` customXml reference + inline-bytes
114
+ * fallback.
115
+ *
116
+ * Default `false`. Offload is OFF unless the host opts in
117
+ * explicitly — supplying a `hostAdapter` for other purposes
118
+ * (chart-preview, save-session, log-event) never silently
119
+ * activates offload work.
120
+ *
121
+ * Rationale: per cross-layer-coord-04 §1.13, sha-256 +
122
+ * base64-encode of a large (2.5 MB) offloadable embedding adds
123
+ * ~300 ms to cold-open. Hosts that genuinely want offload opt in;
124
+ * hosts that only want the adapter for other purposes pay zero.
125
+ */
126
+ offloadEmbeddedDocuments?: boolean;
127
+ /** Per-stage load instrumentation callback. */
128
+ onLoadStage?: (stage: LoadStage, durationMs: number) => void;
129
+ /**
130
+ * Optional telemetry bus. When supplied, the loader brackets every
131
+ * `parseMainDocumentXml` invocation with `setActiveParseTelemetryBus`
132
+ * so the parser emits on the `parse` channel. Typically the same
133
+ * bus is also passed to `createDocumentRuntime({ telemetryBus })`
134
+ * so one bus spans both load and runtime observers.
135
+ *
136
+ * Type signature uses `unknown` so the public session barrel does
137
+ * not drag in runtime-layer type dependencies; the loader narrows
138
+ * to the concrete `TelemetryBus` shape internally.
139
+ */
140
+ telemetryBus?: unknown;
141
+ /**
142
+ * L7 Phase 2.5 Plan B B.6b — optional laycache envelope. When
143
+ * supplied, the loader skips the five expensive parse stages and
144
+ * uses the envelope's canonical document directly. Prefer
145
+ * `tryLaycacheEnvelope: true` over this — with that option the
146
+ * session runs the probe itself. Callers still wanting to supply
147
+ * a pre-probed envelope (e.g. a custom caching layer) can pass it
148
+ * here; when both are set, this wins.
149
+ *
150
+ * Type is `unknown` so the session barrel does not drag runtime
151
+ * layer types into its surface; the loader narrows to the concrete
152
+ * `CacheEnvelope` internally.
153
+ */
154
+ laycacheEnvelope?: unknown;
155
+ /**
156
+ * Run `tryReadLaycacheEnvelope(bytes)` inside `DocxSession.open()`
157
+ * before dispatching to the legacy loader. When the probe returns a
158
+ * validated envelope, the loader short-circuits the five expensive
159
+ * parse stages and uses the cached `canonicalDocument` directly;
160
+ * when it returns null, the full parse runs. The probe itself is
161
+ * ~20–50 ms on extra-large documents.
162
+ *
163
+ * CLAUDE.md Performance Invariant 10: do not insert blocking work
164
+ * between the probe and the loader. Setting this to `true` keeps
165
+ * the two colocated inside the session; callers MUST NOT run a
166
+ * manual probe before `open()` and then also set this flag.
167
+ *
168
+ * Default: `false` (skip the probe; full parse). `laycacheEnvelope`
169
+ * takes precedence when both are set.
170
+ */
171
+ tryLaycacheEnvelope?: boolean;
172
+ /**
173
+ * Callback that runs the laycache-envelope probe on the source
174
+ * bytes. When `tryLaycacheEnvelope: true` is set AND this callback
175
+ * is supplied, the session invokes it (before the full parse) to
176
+ * check whether the package carries a pre-computed laycache
177
+ * envelope. On a hit, the returned `{ envelope }` is used as the
178
+ * short-circuit source; on a miss, full parse runs.
179
+ *
180
+ * Typed as a function returning `unknown` so this session-layer
181
+ * option does not transit `src/runtime/prerender/**` (the concrete
182
+ * `CacheEnvelope` type + `tryReadLaycacheEnvelope` implementation
183
+ * both live under runtime, which §P6 forbids session imports
184
+ * against). The shell / prerender entry-point wires the concrete
185
+ * probe; session narrows opaquely.
186
+ *
187
+ * Slice 5e-11 item-1 introduced this DI seam to retire the last
188
+ * `src/session/session.ts → src/runtime/prerender/customxml-probe.ts`
189
+ * debt exception (cross-layer-coord-01 §1).
190
+ */
191
+ laycacheProbe?: (
192
+ bytes: Uint8Array | ArrayBuffer,
193
+ ) => Promise<{ envelope: unknown } | null>;
194
+ /**
195
+ * Host-adapter Stage 0B.1: optional callback invoked when chart
196
+ * previews have finished resolving off the critical path. Fires
197
+ * with the canonical document that carries the resolved previews;
198
+ * the UI uses this to hydrate the runtime's chart-preview facet
199
+ * without blocking first paint.
200
+ *
201
+ * CLAUDE.md Performance Invariant 9 — do NOT `await` this, and do
202
+ * not rely on it for first-paint correctness. When omitted,
203
+ * chart-preview synthesis runs inline on the load path.
204
+ */
205
+ onChartPreviewsReady?: (resolvedDoc: CanonicalDocument) => void;
206
+ /**
207
+ * C2c progressive-snapshot callback. When supplied AND no cached
208
+ * laycache envelope is in play, the loader fires this once after
209
+ * the body-normalize stage with a viewport-windowed surface snapshot
210
+ * so the UI can paint the first page before the full session
211
+ * resolves. CLAUDE.md Performance Invariant 8 pins the caller-side
212
+ * wiring: the callback MUST be fed through `React.startTransition`
213
+ * and the state slot MUST be cleared before committing the full
214
+ * runtime, or the progressive render turns into a blocking flicker.
215
+ *
216
+ * Only fires on the cold path — `laycacheEnvelope` set (either
217
+ * explicitly or via `tryLaycacheEnvelope`) skips the synthesis
218
+ * because the short-circuit is already fast enough that a
219
+ * pre-commit adds more overhead than it saves.
220
+ */
221
+ onProgressiveSnapshot?: (partial: {
222
+ /**
223
+ * Projected surface. Only populated when `surfaceProjector` is also
224
+ * supplied — the session layer does not own surface projection
225
+ * (architecture §P6: session imports are forbidden from
226
+ * `src/runtime/**`). Consumers that need the projected surface
227
+ * either supply a `surfaceProjector` (recommended) or project the
228
+ * surface themselves from the normalized content available on the
229
+ * final `OpenResult`.
230
+ */
231
+ surface?: EditorSurfaceSnapshot;
232
+ phase: "viewport";
233
+ blocksRealized: number;
234
+ blocksTotal: number;
235
+ }) => void;
236
+ /**
237
+ * Runtime-side port that projects a viewport-windowed
238
+ * `EditorSurfaceSnapshot` from the body-stage normalized content.
239
+ *
240
+ * When supplied with `onProgressiveSnapshot`, the session invokes
241
+ * this port to synthesize the surface before firing the callback.
242
+ * When absent, the session skips the projection and the callback
243
+ * fires with `surface: undefined`. This keeps the session layer
244
+ * P6-clean — surface projection lives in `src/runtime/**`; the
245
+ * session never reaches into it.
246
+ *
247
+ * The `editor-runtime-boundary.ts` load path binds the real
248
+ * projector (`createEditorSurfaceSnapshot` + default selection +
249
+ * `MAIN_STORY_TARGET`) and passes it through here.
250
+ */
251
+ surfaceProjector?: ProgressiveSurfaceProjector;
252
+ /**
253
+ * Override the load scheduler backend. When supplied, the session
254
+ * constructs the internal scheduler with `backendOverride` set to
255
+ * this value; otherwise auto-detect picks the best backend for the
256
+ * current environment (scheduler.yield → MessageChannel →
257
+ * setTimeout → sync).
258
+ *
259
+ * The only caller today is `prerenderDocument` in
260
+ * `src/runtime/prerender/**`, which forces `"sync"` so the staged
261
+ * loader runs without yielding in Node / SSR contexts where
262
+ * determinism matters. Hosts that open interactively should omit
263
+ * this field and let auto-detect run.
264
+ */
265
+ schedulerBackend?: LoadSchedulerBackend;
266
+ }
267
+
268
+ /**
269
+ * Options for `DocxSession.export(doc, opts)`.
270
+ *
271
+ * Reserved as an alias of `ExportDocxOptions` for now. Slice 4 wires
272
+ * export orchestration into `src/session/export/**` and promotes any
273
+ * new fields here; the alias keeps the public surface stable.
274
+ */
275
+ export type ExportOptions = ExportDocxOptions;
276
+
277
+ /**
278
+ * Options for `DocxSession.validate(doc, opts)`.
279
+ *
280
+ * Reserved for Slice 4's export-validation work; the validate entry
281
+ * runs the compatibility engine against a provided canonical document
282
+ * without opening a package. Currently empty; fields expand as the
283
+ * validator wires in.
284
+ */
285
+ export interface ValidateOptions {
286
+ /**
287
+ * Optional profile selector — future validator can emit different
288
+ * report shapes for different target consumers (UI diagnostics panel
289
+ * vs. CI gate vs. export-blocking check).
290
+ */
291
+ profile?: "default" | "export-blocking";
292
+ }
293
+
294
+ /**
295
+ * Reserved opaque snapshot of the preservation store as it stood at
296
+ * open time. Carries enough information to drive round-trip on export.
297
+ *
298
+ * The concrete shape is an alias of the existing `PreservationStore`
299
+ * model type; exposed here so Layer 01 owns the snapshot contract even
300
+ * while the store implementation lives in `src/preservation/**` /
301
+ * `src/model/**`.
302
+ */
303
+ export type PreservationSnapshot = PreservationStore;
304
+
305
+ /**
306
+ * Result of `DocxSession.open(bytes, opts)`. Mirrors the architecture
307
+ * doc exactly: session state + canonical document + compatibility
308
+ * report + preservation snapshot + embedded-document manifest (P8).
309
+ *
310
+ * Every field here is part of the reserved Layer-01 public contract.
311
+ * The transitional legacy-session handle that in-tree services still
312
+ * need during the Slice-4 → Slice-5 migration is carried through a
313
+ * WeakMap-backed accessor (`getLegacyOpenView`) in the
314
+ * `src/session/_internal-legacy.ts` module — NOT as a public field on
315
+ * this shape. The architecture doc has no `_legacy` escape hatch,
316
+ * and public consumers must not see one.
317
+ */
318
+ export interface OpenResult {
319
+ readonly sessionState: EditorSessionState;
320
+ readonly canonicalDocument: CanonicalDocument;
321
+ readonly compatibility: CompatibilityReport;
322
+ readonly preservation: PreservationSnapshot;
323
+ readonly embeddedDocuments: readonly EmbeddedDocumentManifest[];
324
+ /**
325
+ * `true` when the source package declared document protection that
326
+ * makes editing invalid on open (e.g. `readOnly` protection
327
+ * setting). Callers use this to surface a non-interactive view of
328
+ * the document without reaching into the transitional legacy view.
329
+ *
330
+ * Slice 5e-1 promoted this off `LegacyOpenView`.
331
+ */
332
+ readonly readOnly: boolean;
333
+ /**
334
+ * Populated when the parse pipeline produced an unrecoverable error
335
+ * that leaves the session unusable for editing (e.g. OPC structure
336
+ * rejected, main-document.xml not parseable). The session is still
337
+ * returned so callers can show a diagnostic snapshot; presence of
338
+ * this field signals "do not enter the normal runtime path".
339
+ *
340
+ * Slice 5e-1 promoted this off `LegacyOpenView`.
341
+ */
342
+ readonly fatalError?: EditorError;
343
+ /**
344
+ * Snapshot of `/word/settings.xml` document-protection state at
345
+ * open time. Downstream code uses this to gate command availability
346
+ * without re-reading the package.
347
+ *
348
+ * Slice 5e-1 promoted this off `LegacyOpenView`.
349
+ */
350
+ readonly protectionSnapshot: ProtectionSnapshot;
351
+ /**
352
+ * When an internal `tryLaycacheEnvelope` probe hit OR the caller
353
+ * supplied an explicit `laycacheEnvelope` option, the resolved
354
+ * envelope is surfaced here so callers can extract auxiliary data
355
+ * such as the cached layout graph (for `seedLayoutCache`) without
356
+ * re-running the probe.
357
+ *
358
+ * Typed `unknown` so the session barrel does not drag runtime-layer
359
+ * `CacheEnvelope` types into its public surface; callers cast to
360
+ * the concrete shape at the consumption site.
361
+ */
362
+ readonly laycacheEnvelope?: unknown;
363
+ /**
364
+ * Persisted snapshot of the initial session state. Stable
365
+ * serialization envelope that hosts can hand to `load()` on a later
366
+ * mount to rehydrate the same document. Used by snapshot-based
367
+ * persistence flows (session-bootstrap, validator orchestrator,
368
+ * debug harness). Graduated from `LegacyOpenView.initialSnapshot`
369
+ * in Slice 5e-11 item-4.
370
+ */
371
+ readonly initialSnapshot: PersistedEditorSnapshot;
372
+ /**
373
+ * Schema-1.2 editor-state payload parsed from the source package's
374
+ * `customXml/item1.xml` at open time, if present. Hosts use this
375
+ * to rehydrate per-document editor overlays (workflow metadata,
376
+ * scope definitions, host annotations). Present only when the
377
+ * source package carried the schema-1.2 envelope; absent for
378
+ * non-workflow-enabled documents.
379
+ *
380
+ * Graduated from `LegacyOpenView.initialEditorStatePayload` per the
381
+ * L06 `OpenResult` shape decision (2026-04-22, `docs/architecture/
382
+ * 06-workflow-review.md` §"Open-time surface").
383
+ *
384
+ * Typed `unknown` so the session barrel does not drag the
385
+ * `EditorStatePayload` type from `src/io/ooxml/workflow-payload.ts`
386
+ * into its public surface; callers cast at the consumption site.
387
+ */
388
+ readonly initialEditorStatePayload?: unknown;
389
+ /**
390
+ * Export closure bound to this session's captured
391
+ * `ImportedDocxState`. Equivalent to
392
+ * `docxSession.export(sessionState, opts)` — the convenience
393
+ * method avoids requiring hosts to retain a reference to the
394
+ * `DocxSession` instance when they only hold the `OpenResult`.
395
+ * Same result, same byte-reuse fast path, same reconstitute
396
+ * pipeline.
397
+ */
398
+ readonly exportDocx: (
399
+ sessionStateOrSnapshot: EditorSessionState | PersistedEditorSnapshot,
400
+ opts?: ExportOptions,
401
+ ) => Promise<ExportResult>;
402
+ /**
403
+ * Releases any pending idle callbacks the load scheduler queued
404
+ * during parse. Callers SHOULD invoke on unmount to cancel
405
+ * in-flight off-critical-path work (chart-preview resolution,
406
+ * etc.) — CLAUDE.md Performance Invariant 9. Optional because the
407
+ * sync scheduler backend (used by `prerenderDocument`) has nothing
408
+ * to cancel.
409
+ *
410
+ * Equivalent to calling `docxSession.dispose()` on the owning
411
+ * `DocxSession` instance.
412
+ */
413
+ readonly dispose?: () => void;
414
+ }
415
+
416
+ /**
417
+ * Sentinel returned by `DocxSession.reopenFromSnapshot()` when the
418
+ * rehydrate path cannot produce a usable `OpenResult`. Never thrown —
419
+ * always returned as a data value so callers can diff + display
420
+ * without a try/catch envelope.
421
+ *
422
+ * Discriminant: presence of `reason` — the `OpenResult` shape has no
423
+ * `reason` field. Consumers: `if ("reason" in result) { /* barrier *\/ }`.
424
+ */
425
+ export interface ReopenBarrier {
426
+ /**
427
+ * Coarse-grained reason enum. Stable across minor versions;
428
+ * additive changes only. Hosts typically map this to a localized
429
+ * UI message and/or an audit event.
430
+ */
431
+ readonly reason:
432
+ | "no-source-package"
433
+ | "invalid-digest"
434
+ | "corrupted-bytes"
435
+ | "unsupported-schema";
436
+ /**
437
+ * Human-readable explanation tied to `reason`. Stable enough for
438
+ * surfacing verbatim in diagnostic logs. Not localised.
439
+ */
440
+ readonly message: string;
441
+ }
442
+
443
+ /**
444
+ * Type guard helper — narrows `OpenResult | ReopenBarrier` to the
445
+ * barrier arm. The discriminant is the presence of `reason`.
446
+ */
447
+ export function isReopenBarrier(
448
+ result: OpenResult | ReopenBarrier,
449
+ ): result is ReopenBarrier {
450
+ return (result as Partial<ReopenBarrier>).reason !== undefined;
451
+ }
452
+
453
+ /**
454
+ * Result of `DocxSession.validate(doc, opts)`.
455
+ *
456
+ * Reserved shape — Slice 4 implements the runner and decides whether
457
+ * findings carry line/column context or only stable codes. The field
458
+ * list here is the minimum the architecture needs: a severity-tagged
459
+ * record list plus a pass/fail verdict.
460
+ */
461
+ export interface ValidationReport {
462
+ readonly ok: boolean;
463
+ readonly findings: readonly ValidationFinding[];
464
+ }
465
+
466
+ export interface ValidationFinding {
467
+ readonly code: string;
468
+ readonly severity: "info" | "warning" | "error";
469
+ readonly message: string;
470
+ readonly featureKey?: string;
471
+ }
472
+
473
+ // ---------------------------------------------------------------------------
474
+ // P8 · Embedded-document manifest (architecture §P8)
475
+ // ---------------------------------------------------------------------------
476
+
477
+ /**
478
+ * Per-entry shape for every embedded OLE object or `w:altChunk` target
479
+ * discovered on open. Matches the reservation at
480
+ * `docs/architecture/01-package-session.md` § Public entry points:
481
+ * - `id` stable across open/export (derived from content fingerprint)
482
+ * - `kind` three-way classification from `classifyEmbedding()`
483
+ * - `progId`, `mimeType`, `filename` are signal-best-effort metadata
484
+ * - `size` is the byte length of the underlying package part
485
+ * - `relationshipId` points to the owning rId in the main-document
486
+ * relationships (or the containing story for altChunk targets)
487
+ * - `bytes()` is lazy — the part bytes are materialized on demand,
488
+ * never eagerly copied at open time (Performance Invariant 9)
489
+ */
490
+ export interface EmbeddedDocumentManifest {
491
+ readonly id: string;
492
+ readonly kind: EmbeddingKind;
493
+ readonly progId?: string;
494
+ readonly mimeType?: string;
495
+ readonly filename?: string;
496
+ readonly size: number;
497
+ readonly relationshipId: string;
498
+ readonly bytes: () => Uint8Array;
499
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Shell helper — chart-snapshot projection.
3
+ *
4
+ * Walks a `CanonicalDocument` and projects the chart-preview inlines into
5
+ * public-API `ChartSnapshot` records. Consumers: the React editor ref
6
+ * (`getChartSnapshots` / `getChartSnapshot`) and any headless consumer
7
+ * that needs chart reads without mounting the editor.
8
+ *
9
+ * This lives in `src/shell/` rather than `src/ui/` because it's a pure
10
+ * projection between the canonical document (L02) and the public API
11
+ * (L07 reads) — no DOM, no React, no presentation. `src/ui/` is the
12
+ * presentation layer; keeping this helper outside it retires two
13
+ * substrate-reach-through imports (`runtime/chart/chart-model-store` +
14
+ * `runtime/chart/chart-snapshot`) from the Layer-11 boundary register.
15
+ */
16
+
17
+ import type { CanonicalDocument } from "../model/canonical-document.ts";
18
+ import type { ChartSnapshot } from "../api/public-types.ts";
19
+ import { stableChartId } from "../runtime/chart/chart-model-store.ts";
20
+ import { projectChartSnapshot } from "../runtime/chart/chart-snapshot.ts";
21
+
22
+ type BlockArray = CanonicalDocument["content"]["children"];
23
+
24
+ export function collectChartSnapshots(doc: CanonicalDocument): ChartSnapshot[] {
25
+ const results: ChartSnapshot[] = [];
26
+ collectChartSnapshotsFromBlocks(doc.content.children, results);
27
+ return results;
28
+ }
29
+
30
+ /**
31
+ * Walk the canonical document, compute each chart_preview's stableChartId,
32
+ * and project a snapshot for the first matching id. Short-circuits on
33
+ * match so the happy path is O(k) in blocks-until-match rather than the
34
+ * O(N) the `collect().find()` fallback incurred for every ref call. For
35
+ * hosts that call `getChartSnapshot` in a tight loop over many chartIds,
36
+ * this reduces the cost from O(N²) to O(N·k).
37
+ */
38
+ export function lookupChartSnapshot(
39
+ doc: CanonicalDocument,
40
+ chartId: string,
41
+ ): ChartSnapshot | null {
42
+ return lookupChartSnapshotInBlocks(doc.content.children, chartId);
43
+ }
44
+
45
+ function lookupChartSnapshotInBlocks(
46
+ blocks: BlockArray,
47
+ chartId: string,
48
+ ): ChartSnapshot | null {
49
+ for (const block of blocks) {
50
+ if (block.type === "paragraph") {
51
+ for (const inline of block.children) {
52
+ if (inline.type === "chart_preview" && inline.parsedData) {
53
+ const id = stableChartId(inline.rawXml);
54
+ if (id === chartId) {
55
+ return projectChartSnapshot(id, inline.parsedData);
56
+ }
57
+ }
58
+ }
59
+ } else if (block.type === "table") {
60
+ for (const row of block.rows) {
61
+ for (const cell of row.cells) {
62
+ const found = lookupChartSnapshotInBlocks(cell.children, chartId);
63
+ if (found) return found;
64
+ }
65
+ }
66
+ } else if (block.type === "sdt" || block.type === "custom_xml") {
67
+ const found = lookupChartSnapshotInBlocks(block.children, chartId);
68
+ if (found) return found;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ function collectChartSnapshotsFromBlocks(
75
+ blocks: BlockArray,
76
+ results: ChartSnapshot[],
77
+ ): void {
78
+ for (const block of blocks) {
79
+ if (block.type === "paragraph") {
80
+ for (const inline of block.children) {
81
+ if (inline.type === "chart_preview" && inline.parsedData) {
82
+ const chartId = stableChartId(inline.rawXml);
83
+ results.push(projectChartSnapshot(chartId, inline.parsedData));
84
+ }
85
+ }
86
+ } else if (block.type === "table") {
87
+ for (const row of block.rows) {
88
+ for (const cell of row.cells) {
89
+ collectChartSnapshotsFromBlocks(cell.children, results);
90
+ }
91
+ }
92
+ } else if (block.type === "sdt" || block.type === "custom_xml") {
93
+ collectChartSnapshotsFromBlocks(block.children, results);
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Shell helper — media-preview catalog construction.
3
+ *
4
+ * Builds the inline `data:` URLs the mounted editor feeds to image
5
+ * render paths. Reads the persisted source-package bytes, verifies the
6
+ * digest, walks the OPC parts table, and projects each canonical media
7
+ * item into a `MediaPreviewDescriptor`.
8
+ *
9
+ * SVG is included in the browser-safe content-type allowlist — Chromium
10
+ * sandboxes SVGs loaded via `<img src="data:image/svg+xml;base64,…">`
11
+ * (no script execution, no external refs), so XSS surface matches PNG.
12
+ * Required for CCEP-synthesized chart previews (Stage 0B) and hosts
13
+ * that ship `.svg` inside `word/media/`.
14
+ *
15
+ * Lives in `src/shell/` so the three `io/**` substrate imports stay
16
+ * outside the L11 boundary register — package decoding is a shell
17
+ * concern, not a presentation one.
18
+ */
19
+
20
+ import type { CanonicalDocument } from "../model/canonical-document.ts";
21
+ import type { PersistedSourcePackage } from "../model/snapshot.ts";
22
+ import type { MediaPreviewDescriptor } from "../ui-tailwind/editor-surface/pm-state-from-snapshot";
23
+ import {
24
+ decodePersistedSourcePackageBytes,
25
+ hasValidPersistedSourcePackageDigest,
26
+ } from "../io/source-package-provenance.ts";
27
+ import { readOpcPackage } from "../io/opc/package-reader.ts";
28
+
29
+ const BROWSER_SAFE_PREVIEW_TYPES = new Set([
30
+ "image/png",
31
+ "image/jpeg",
32
+ "image/jpg",
33
+ "image/gif",
34
+ "image/webp",
35
+ "image/bmp",
36
+ "image/svg+xml",
37
+ ]);
38
+
39
+ export function buildMediaPreviews(
40
+ sourcePackage: PersistedSourcePackage | null | undefined,
41
+ canonicalDocument: CanonicalDocument,
42
+ ): Record<string, MediaPreviewDescriptor> {
43
+ if (!sourcePackage) {
44
+ return {};
45
+ }
46
+ try {
47
+ const bytes = decodePersistedSourcePackageBytes(sourcePackage);
48
+ if (!hasValidPersistedSourcePackageDigest(sourcePackage, bytes)) {
49
+ return {};
50
+ }
51
+ const opc = readOpcPackage(bytes);
52
+ const previews: Record<string, MediaPreviewDescriptor> = {};
53
+ for (const item of Object.values(canonicalDocument.media.items)) {
54
+ const contentType = item.contentType?.toLowerCase();
55
+ const part = opc.parts.get(item.packagePartName);
56
+ if (
57
+ !part?.bytes ||
58
+ !contentType ||
59
+ !BROWSER_SAFE_PREVIEW_TYPES.has(contentType)
60
+ ) {
61
+ continue;
62
+ }
63
+ previews[item.mediaId] = {
64
+ src: createImageDataUrl(contentType, part.bytes),
65
+ ...(item.widthEmu !== undefined ? { widthEmu: item.widthEmu } : {}),
66
+ ...(item.heightEmu !== undefined ? { heightEmu: item.heightEmu } : {}),
67
+ };
68
+ }
69
+ return previews;
70
+ } catch {
71
+ return {};
72
+ }
73
+ }
74
+
75
+ function createImageDataUrl(contentType: string, bytes: Uint8Array): string {
76
+ return `data:${contentType};base64,${bytesToBase64(bytes)}`;
77
+ }
78
+
79
+ function bytesToBase64(bytes: Uint8Array): string {
80
+ let binary = "";
81
+ for (let index = 0; index < bytes.length; index += 1) {
82
+ binary += String.fromCharCode(bytes[index] ?? 0);
83
+ }
84
+ return btoa(binary);
85
+ }